Merge "Remove property _showInlineDiff"
diff --git a/Documentation/access-control.txt b/Documentation/access-control.txt
index 2a019ca..3da69df 100644
--- a/Documentation/access-control.txt
+++ b/Documentation/access-control.txt
@@ -477,6 +477,11 @@
`+refs/heads/sandbox/${username}/*+`. If you do, it's also recommended
you grant the users the push force permission to be able to clean up
stale branches.
+If link:config-gerrit.html#auth.userNameCaseInsensitive[auth.userNameCaseInsensitive]
+is enabled, the `${username}` is still case sensitive and will use
+the capitalization used during account creation. This is done, since
+git branches are case sensitive, so that sandbox branches containing
+`${username}` are still reachable by the users.
[[category_delete]]
=== Delete Reference
diff --git a/Documentation/cmd-set-account.txt b/Documentation/cmd-set-account.txt
index 6808e017..02eaf83 100644
--- a/Documentation/cmd-set-account.txt
+++ b/Documentation/cmd-set-account.txt
@@ -14,7 +14,8 @@
[--delete-ssh-key - | <KEY> | ALL]
[--generate-http-password]
[--http-password <PASSWORD>]
- [--clear-http-password] <USER>
+ [--clear-http-password]
+ [--delete-external-id <EXTERNALID>] <USER>
--
== DESCRIPTION
@@ -106,6 +107,13 @@
--clear-http-password::
Clear the HTTP password for the user account.
+--delete-external-id::
+ Delete an external ID from a user's account if it exists.
+ If the external ID provided is 'ALL', all associated
+ external IDs are deleted from this account.
+ May be supplied more than once to remove multiple external
+ IDs from an account in a single command execution.
+
== EXAMPLES
Add an email and SSH key to `watcher`'s account:
diff --git a/Documentation/config-accounts.txt b/Documentation/config-accounts.txt
index 9b99960..7a7cef2 100644
--- a/Documentation/config-accounts.txt
+++ b/Documentation/config-accounts.txt
@@ -3,8 +3,7 @@
== Overview
-Starting from 2.15 Gerrit accounts are fully stored in
-link:note-db.html[NoteDb].
+Gerrit accounts are stored in link:note-db.html[NoteDb].
The account data consists of a sequence number (account ID), account
properties (full name, display name, preferred email, registration
@@ -298,6 +297,13 @@
This ensures that an external ID is used only once (e.g. an external ID can
never be assigned to multiple accounts at a point in time).
+By default, the SHA-1 sum is computed preserving the case of the external ID. If
+auth.userNameCaseInsensitive` is set to `true`, the SHA-1 sum of external IDs
+in the `gerrit:` and `username:` schemes are computed from the all lowercase
+external ID. This enables case insensitive username handling. The case of the
+external ID is however preserved by using the original capitalization in the
+note content.
+
The following commands show how to find the SHA-1 of an external ID:
----
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 32867b6..76e1f82 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -652,6 +652,32 @@
+
By default this is set to false.
+[[auth.userNameCaseInsensitive]]auth.userNameCaseInsensitive::
++
+If set the username will be handled case insensitively but case preserving,
+i.e. a user can login with `johndoe` or `JohnDoe` for the same account
+created for `JohnDoe`. The form of the username used during account creation
+will be used wherever the username is displayed. Sandbox branches created
+for a user can also only be created for this original form.
++
+Note, that this does not work for all existing accounts, if they were
+not originally created with all lowercase, since the note keys of the
+external IDs will not match the new scheme. For more details refer to
+the link:config-accounts.html#external-ids[External ID documentation].
++
+Gerrit provides the
+link:pgm-ChangeExternalIdCaseSensitivity.html[ChangeExternalIdCaseSensitivity tool]
+to migrate existing accounts to match the new scheme.
++
+Naturally, if there were two accounts only different in capitalization,
+e.g. `johndoe` and `JohnDoe`, the account `JohnDoe` will not be able
+to authenticate anymore after setting this option. If such duplicate
+accounts exist the migration tool will fail, since the newly computed
+note name would be identical and thus conflict. These duplicates thus
+have to be deleted manually by deleting the respective external ID.
++
+Default is false.
+
[[auth.enableRunAs]]auth.enableRunAs::
+
If true HTTP REST APIs will accept the `X-Gerrit-RunAs` HTTP request
@@ -4454,8 +4480,7 @@
[[retry.retryWithTraceOnFailure]]retry.retryWithTraceOnFailure::
+
Whether Gerrit should automatically retry operations on failure with tracing
-enabled. The automatically generated traces can help with debugging. Please
-note that only some of the REST endpoints support automatic retry.
+enabled. The automatically generated traces can help with debugging.
+
By default this is set to false.
@@ -5315,13 +5340,27 @@
[[tracing.traceid.requestUriPattern]]tracing.<trace-id>.requestUriPattern::
+
Regular expression to match request URIs for which request tracing
-should be always enabled. Request URIs are only available for REST
-requests. Request URIs never include the '/a' prefix.
+should be enabled except if they match
+link:tracing.traceid.excludedRequestUriPattern[excludedRequestUriPattern].
+Request URIs are only available for REST requests. Request URIs never include
+the '/a' prefix.
+
May be specified multiple times.
+
By default, unset (all request URIs are matched).
+[[tracing.traceid.excludedRequestUriPattern]]tracing.<trace-id>.excludedRequestUriPattern::
++
+Regular expression to match request URIs for which request tracing
+should not be enabled even if they match
+link:#tracing.traceid.requestUriPattern[requestUriPattern].
+Request URIs are only available for REST requests. Request URIs never include
+the '/a' prefix.
++
+May be specified multiple times.
++
+By default, unset (no request URIs are excluded).
+
[[tracing.traceid.account]]tracing.<trace-id>.account::
+
Account ID of an account for which request tracing should be always
@@ -5388,7 +5427,9 @@
[[deadline.id.requestUriPattern]]deadline.<id>.requestUriPattern::
+
-Regular expression to match request URIs to which the deadline applies. Request
+Regular expression to match request URIs to which the deadline applies except if
+they match
+link:#deadline.id.excludedRequestUriPattern[excludedRequestUriPattern]. Request
URIs are only available for REST requests. Request URIs never include the '/a'
prefix.
+
@@ -5396,6 +5437,17 @@
+
By default, unset (all request URIs are matched).
+[[deadline.id.excludedRequestUriPattern]]deadline.<id>.excludedRequestUriPattern::
++
+Regular expression to match request URIs to which the deadline should not be
+applied even if they match
+link:#deadline.id.requestUriPattern[requestUriPattern]. Request URIs are only
+available for REST requests. Request URIs never include the '/a' prefix.
++
+May be specified multiple times.
++
+By default, unset (no request URIs are excluded).
+
[[deadline.id.account]]deadline.<id>.account::
+
Account ID of an account to which the deadline applies.
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 992d459..fa2b78c 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -74,9 +74,9 @@
manifest fields:
----
- Implementation-Title: Example plugin showing examples
- Implementation-Version: 1.0
- Implementation-Vendor: Example, Inc.
+Implementation-Title: Example plugin showing examples
+Implementation-Version: 1.0
+Implementation-Vendor: Example, Inc.
----
=== ApiType
@@ -88,7 +88,7 @@
loading a plugin that needs the plugin API.
----
- Gerrit-ApiType: plugin
+Gerrit-ApiType: plugin
----
=== Explicit Registration
@@ -103,9 +103,9 @@
`@Listen` and `@Export("")` annotations.
----
- Gerrit-Module: tld.example.project.CoreModuleClassName
- Gerrit-SshModule: tld.example.project.SshModuleClassName
- Gerrit-HttpModule: tld.example.project.HttpModuleClassName
+Gerrit-Module: tld.example.project.CoreModuleClassName
+Gerrit-SshModule: tld.example.project.SshModuleClassName
+Gerrit-HttpModule: tld.example.project.HttpModuleClassName
----
=== Batch runtime
@@ -120,7 +120,7 @@
offline reindexing task.
----
- Gerrit-BatchModule: tld.example.project.CoreModuleClassName
+Gerrit-BatchModule: tld.example.project.CoreModuleClassName
----
In this runtime, only the module designated by `Gerrit-BatchModule` is
@@ -132,7 +132,7 @@
A plugin can optionally provide its own plugin name.
----
- Gerrit-PluginName: replication
+Gerrit-PluginName: replication
----
This is useful for plugins that contribute plugin-owned capabilities that
@@ -218,7 +218,7 @@
with no down time.
----
- Gerrit-ReloadMode: restart
+Gerrit-ReloadMode: restart
----
In either mode ('restart' or 'reload') any plugin or extension can
@@ -261,7 +261,7 @@
credentials and possibly verify connectivity to validate them.
----
- Gerrit-InitStep: tld.example.project.MyInitStep
+Gerrit-InitStep: tld.example.project.MyInitStep
----
MyInitStep needs to follow the standard Gerrit InitStep syntax
@@ -278,37 +278,37 @@
[source,java]
----
- public class MyInitStep implements InitStep {
- private final String pluginName;
- private final ConsoleUI ui;
- private final AllProjectsConfig allProjectsConfig;
+public class MyInitStep implements InitStep {
+ private final String pluginName;
+ private final ConsoleUI ui;
+ private final AllProjectsConfig allProjectsConfig;
- @Inject
- public MyInitStep(@PluginName String pluginName, ConsoleUI ui,
- AllProjectsConfig allProjectsConfig) {
- this.pluginName = pluginName;
- this.ui = ui;
- this.allProjectsConfig = allProjectsConfig;
- }
-
- @Override
- public void run() throws Exception {
- }
-
- @Override
- public void postRun() throws Exception {
- ui.message("\n");
- ui.header(pluginName + " Integration");
- boolean enabled = ui.yesno(true, "By default enabled for all projects");
- Config cfg = allProjectsConfig.load().getConfig();
- if (enabled) {
- cfg.setBoolean("plugin", pluginName, "enabled", enabled);
- } else {
- cfg.unset("plugin", pluginName, "enabled");
- }
- allProjectsConfig.save(pluginName, "Initialize " + pluginName + " Integration");
- }
+ @Inject
+ public MyInitStep(@PluginName String pluginName, ConsoleUI ui,
+ AllProjectsConfig allProjectsConfig) {
+ this.pluginName = pluginName;
+ this.ui = ui;
+ this.allProjectsConfig = allProjectsConfig;
}
+
+ @Override
+ public void run() throws Exception {
+ }
+
+ @Override
+ public void postRun() throws Exception {
+ ui.message("\n");
+ ui.header(pluginName + " Integration");
+ boolean enabled = ui.yesno(true, "By default enabled for all projects");
+ Config cfg = allProjectsConfig.load().getConfig();
+ if (enabled) {
+ cfg.setBoolean("plugin", pluginName, "enabled", enabled);
+ } else {
+ cfg.unset("plugin", pluginName, "enabled");
+ }
+ allProjectsConfig.save(pluginName, "Initialize " + pluginName + " Integration");
+ }
+}
----
Bear in mind that the Plugin's InitStep class will be loaded but
@@ -706,9 +706,12 @@
in between, leading to the final operator name. An example
registration looks like this:
- bind(ChangeOperatorFactory.class)
- .annotatedWith(Exports.named("sample"))
- .to(SampleOperator.class);
+[source,java]
+----
+bind(ChangeOperatorFactory.class)
+ .annotatedWith(Exports.named("sample"))
+ .to(SampleOperator.class);
+----
If this is registered in the `myplugin` plugin, then the resulting
operator will be named `sample_myplugin`.
@@ -736,7 +739,7 @@
----
[[search_operands]]
-=== Search Operands ===
+== Search Operands
Plugins can define new search operands to extend change searching.
Plugin methods implementing search operands (returning a
@@ -748,31 +751,33 @@
a module's `configure()` method in the plugin.
The new operand, when used in a search would appear as:
- operatorName:operandName_pluginName
+ `operatorName:operandName_pluginName`
A sample `ChangeHasOperandFactory` class implementing, and registering, a
new `has:sample_pluginName` operand is shown below:
-====
- public class SampleHasOperand implements ChangeHasOperandFactory {
- public static class Module extends AbstractModule {
- @Override
- protected void configure() {
- bind(ChangeHasOperandFactory.class)
- .annotatedWith(Exports.named("sample")
- .to(SampleHasOperand.class);
- }
- }
-
+[source, java]
+----
+public class SampleHasOperand implements ChangeHasOperandFactory {
+ public static class Module extends AbstractModule {
@Override
- public Predicate<ChangeData> create(ChangeQueryBuilder builder)
- throws QueryParseException {
- return new HasSamplePredicate();
+ protected void configure() {
+ bind(ChangeHasOperandFactory.class)
+ .annotatedWith(Exports.named("sample")
+ .to(SampleHasOperand.class);
}
-====
+ }
+
+ @Override
+ public Predicate<ChangeData> create(ChangeQueryBuilder builder)
+ throws QueryParseException {
+ return new HasSamplePredicate();
+ }
+}
+----
[[command_options]]
-=== Command Options ===
+== Command Options
Plugins can provide additional options for each of the gerrit ssh and the
REST API commands by implementing the DynamicBean interface and registering
@@ -801,6 +806,7 @@
logger.atSevere().log("Say Hello in the Log %s", arg);
}
}
+}
----
To provide additional Guice bindings for options to a command in another classloader, bind a
@@ -815,21 +821,21 @@
[source, java]
----
- bind(DynamicOptions.DynamicBean.class)
- .annotatedWith(Exports.named(
- "com.google.gerrit.plugins.otherplugin.command"))
- .to(MyOptionsModulesClassNamesProvider.class);
+bind(DynamicOptions.DynamicBean.class)
+ .annotatedWith(Exports.named(
+ "com.google.gerrit.plugins.otherplugin.command"))
+ .to(MyOptionsModulesClassNamesProvider.class);
- static class MyOptionsModulesClassNamesProvider implements DynamicOptions.ModulesClassNamesProvider {
- {@literal @}Override
- public String getClassName() {
- return "com.googlesource.gerrit.plugins.myplugin.CommandOptions";
- }
- {@literal @}Override
- public Iterable<String> getModulesClassNames()() {
- return "com.googlesource.gerrit.plugins.myplugin.MyOptionsModule";
- }
+static class MyOptionsModulesClassNamesProvider implements DynamicOptions.ModulesClassNamesProvider {
+ @Override
+ public String getClassName() {
+ return "com.googlesource.gerrit.plugins.myplugin.CommandOptions";
}
+ @Override
+ public Iterable<String> getModulesClassNames()() {
+ return "com.googlesource.gerrit.plugins.myplugin.MyOptionsModule";
+ }
+}
----
=== Calling Command Options ===
@@ -891,7 +897,7 @@
----
[[query_attributes]]
-=== Change Attributes ===
+== Change Attributes
==== ChangePluginDefinedInfoFactory
@@ -967,13 +973,9 @@
}
----
-Example
+Example:
----
-
-ssh -p 29418 localhost gerrit query --myplugin-name--all "change:1" --format json
-
-Output:
-
+$ ssh -p 29418 localhost gerrit query --myplugin-name--all "change:1" --format json
{
"url" : "http://localhost:8080/1",
"plugins" : [
@@ -986,10 +988,7 @@
...
}
-curl http://localhost:8080/changes/1?myplugin-name--all
-
-Output:
-
+$ curl http://localhost:8080/changes/1?myplugin-name--all
{
"_number": 1,
...
@@ -1133,8 +1132,8 @@
`plugin.helloworld` subsection:
----
- [plugin "helloworld"]
- enabled = true
+[plugin "helloworld"]
+ enabled = true
----
Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
@@ -1337,7 +1336,7 @@
Here and example of ref-updated JSON event payload with `instanceId`:
[source,json]
----
+----
{
"submitter": {
"name": "Administrator",
@@ -1354,7 +1353,7 @@
"eventCreatedOn": 1588849085,
"instanceId": "instance1"
}
----
+----
[[capabilities]]
== Plugin Owned Capabilities
@@ -1681,11 +1680,11 @@
can be accessed from any REST client, i. e.:
----
- curl -X POST -H "Content-Type: application/json" \
+$ curl -X POST -H "Content-Type: application/json" \
-d '{message: "François", french: true}' \
--user joe:secret \
http://host:port/a/changes/1/revisions/1/cookbook~say-hello
- "Bonjour François from change 1, patch set 1!"
+"Bonjour François from change 1, patch set 1!"
----
A special case is to bind an endpoint without a view name. This is
@@ -1782,7 +1781,6 @@
[source,java]
----
public class MyTopMenuExtension implements TopMenu {
-
@Override
public List<MenuEntry> getEntries() {
return Lists.newArrayList(
@@ -1799,7 +1797,6 @@
[source,java]
----
public class MyTopMenuExtension implements TopMenu {
-
@Override
public List<MenuEntry> getEntries() {
return Lists.newArrayList(
@@ -1817,17 +1814,17 @@
specific requests and add an menu item for this:
[source,java]
----
- new MenuItem("My Screen", "/plugins/myplugin/project/${projectName}");
----
+----
+new MenuItem("My Screen", "/plugins/myplugin/project/${projectName}");
+----
This also enables plugins to provide menu items for project aware
screens:
[source,java]
----
- new MenuItem("My Screen", "/x/my-screen/for/${projectName}");
----
+----
+new MenuItem("My Screen", "/x/my-screen/for/${projectName}");
+----
If no Guice modules are declared in the manifest, the top menu extension may use
auto-registration by providing an `@Listen` annotation:
@@ -2041,7 +2038,6 @@
bind(AccountExternalIdCreator.class)
.annotatedWith(UniqueAnnotations.create())
.to(MyExternalIdCreator.class);
-}
----
[[download-commands]]
@@ -2108,7 +2104,6 @@
@Listen
public class MyWeblinkPlugin implements PatchSetWebLink {
-
private String name = "MyLink";
private String placeHolderUrlProjectCommit = "http://my.tool.com/project=%s/commit=%s";
private String imageUrl = "http://placehold.it/16x16.gif";
@@ -2189,7 +2184,6 @@
import com.google.inject.servlet.ServletModule;
public class HttpModule extends ServletModule {
-
@Override
protected void configureServlets() {
serveRegex(URL_REGEX).with(LfsApiServlet.class);
@@ -2200,7 +2194,7 @@
import org.eclipse.jgit.lfs.server.s3.S3Repository;
public class S3LargeFileRepository extends S3Repository {
-...
+ ...
}
----
@@ -2250,8 +2244,8 @@
file. For example:
----
- [plugin "my-plugin"]
- metricsPrefix = my-metrics
+[plugin "my-plugin"]
+ metricsPrefix = my-metrics
----
will cause the metrics to be recorded under `my-metrics/${metric-name}`.
@@ -2274,6 +2268,7 @@
implementation, e.g. one that supports cluster setup with multiple
primary Gerrit nodes handling write operations.
+[source,java]
----
DynamicItem.bind(binder(), AccountPatchReviewStore.class)
.to(MultiMasterAccountPatchReviewStore.class);
@@ -2521,6 +2516,26 @@
}
----
+
+[[account-tag]]
+== Account Tag Plugins
+
+Gerrit provides an extension point that enables Plugins to supply additional
+tags on an account.
+
+[source, java]
+----
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.AccountTagProvider;
+import java.util.List;
+
+public class MyPlugin implements AccountTagProvider {
+ public List<String> getTags(Account.Id id) {
+ // Implement your logic here
+ }
+}
+----
+
[[ssh-command-creation-interception]]
== SSH Command Creation Interception
@@ -2536,6 +2551,8 @@
@Override
public String intercept(String in) {
return pluginName + " mycommand";
+ }
+}
----
[[ssh-command-execution-interception]]
@@ -2569,7 +2586,8 @@
And then declare it in your SSH module:
[source, java]
----
- DynamicSet.bind(binder(), SshExecuteCommandInterceptor.class).to(SshExecuteCommandInterceptorImpl.class);
+DynamicSet.bind(binder(), SshExecuteCommandInterceptor.class)
+ .to(SshExecuteCommandInterceptorImpl.class);
----
[[pre-submit-evaluator]]
diff --git a/Documentation/dev-stars.txt b/Documentation/dev-stars.txt
index a83ad44..764e326 100644
--- a/Documentation/dev-stars.txt
+++ b/Documentation/dev-stars.txt
@@ -29,9 +29,6 @@
There are link:rest-api-accounts.html#default-star-endpoints[
additional REST endpoints] for the link:#default-star[default star].
-Only the link:#default-star[default star] is shown in the WebUI and
-can be updated from there. Other stars do not show up in the WebUI.
-
[[default-star]]
== Default Star
@@ -61,36 +58,11 @@
The ignore star is represented by the special star label 'ignore'.
-[[reviewed-star]]
-== Reviewed Star
-
-If the "reviewed/<patchset_id>"-star is set by a user, and <patchset_id>
-matches the current patch set, the change is always reported as "reviewed"
-in the ChangeInfo.
-
-This allows users to "de-highlight" changes in a dashboard until a new
-patchset has been uploaded.
-
-[[unreviewed-star]]
-== Unreviewed Star
-
-If the "unreviewed/<patchset_id>"-star is set by a user, and <patchset_id>
-matches the current patch set, the change is always reported as "unreviewed"
-in the ChangeInfo.
-
-This allows users to "highlight" changes in a dashboard.
-
[[query-stars]]
== Query Stars
There are several query operators to find changes with stars:
-* link:user-search.html#star[star:<LABEL>]:
- Matches any change that was starred by the current user with the
- label `<LABEL>`.
-* link:user-search.html#has-stars[has:stars]:
- Matches any change that was starred by the current user with any
- label.
* link:user-search.html#is-starred[is:starred] /
link:user-search.html#has-star[has:star]:
Matches any change that was starred by the current user with the
diff --git a/Documentation/index.txt b/Documentation/index.txt
index dc94b14..782a6a9 100644
--- a/Documentation/index.txt
+++ b/Documentation/index.txt
@@ -77,6 +77,7 @@
. link:pgm-index.html[Server Side Administrative Tools]
. link:repository-maintenance.html[Repository Maintenance]
. link:user-request-tracing.html[Request Tracing]
+. link:user-request-cancellation-and-deadlines.html[Request Cancellation and Deadlines]
. link:note-db.html[NoteDb]
. link:config-accounts.html[Accounts on NoteDb]
. link:config-groups.html[Groups on NoteDb]
diff --git a/Documentation/js_licenses.txt b/Documentation/js_licenses.txt
index 3953737..ab79c8f 100644
--- a/Documentation/js_licenses.txt
+++ b/Documentation/js_licenses.txt
@@ -252,6 +252,7 @@
* @types/resemblejs
* @types/resize-observer-browser
+* @types/trusted-types
[[DefinitelyTyped_license]]
----
@@ -280,6 +281,48 @@
----
+[[Lit]]
+Lit
+
+* @lit/reactive-element
+* lit
+* lit-element
+* lit-html
+
+[[Lit_license]]
+----
+BSD 3-Clause License
+
+Copyright (c) 2017 Google LLC. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
[[Polymer-2014]]
Polymer-2014
@@ -1141,84 +1184,6 @@
----
-[[lit-element]]
-lit-element
-
-* lit-element
-
-[[lit-element_license]]
-----
-BSD 3-Clause License
-
-Copyright (c) 2017, The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----
-
-
-[[lit-html]]
-lit-html
-
-* lit-html
-
-[[lit-html_license]]
-----
-BSD 3-Clause License
-
-Copyright (c) 2017, The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----
-
-
[[page]]
page
diff --git a/Documentation/licenses.txt b/Documentation/licenses.txt
index 476751c..86ff904 100644
--- a/Documentation/licenses.txt
+++ b/Documentation/licenses.txt
@@ -3211,6 +3211,7 @@
* @types/resemblejs
* @types/resize-observer-browser
+* @types/trusted-types
[[DefinitelyTyped_license]]
----
@@ -3239,6 +3240,48 @@
----
+[[Lit]]
+Lit
+
+* @lit/reactive-element
+* lit
+* lit-element
+* lit-html
+
+[[Lit_license]]
+----
+BSD 3-Clause License
+
+Copyright (c) 2017 Google LLC. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+----
+
+
[[Polymer-2014]]
Polymer-2014
@@ -4100,84 +4143,6 @@
----
-[[lit-element]]
-lit-element
-
-* lit-element
-
-[[lit-element_license]]
-----
-BSD 3-Clause License
-
-Copyright (c) 2017, The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----
-
-
-[[lit-html]]
-lit-html
-
-* lit-html
-
-[[lit-html_license]]
-----
-BSD 3-Clause License
-
-Copyright (c) 2017, The Polymer Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
- list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
-* Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-----
-
-
[[page]]
page
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index 03be71e..36b3473 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -12,32 +12,121 @@
* `build/label`: Version of Gerrit server software.
* `events`: Triggered events.
+** `type`:
+ The type of the event.
=== Actions
* `action/retry_attempt_count`: Number of retry attempts made
-by RetryHelper to execute an action (0 == single attempt, no retry)
+ by RetryHelper to execute an action (0 == single attempt, no retry)
+** `action_type`:
+ The type of the action that was retried.
+** `operation_name`:
+ The name of the operation that was retried.
+** `cause`:
+ The original cause that triggered the retry.
* `action/retry_timeout_count`: Number of action executions of RetryHelper
-that ultimately timed out
+ that ultimately timed out
+** `action_type`:
+ The type of the action that was retried.
+** `operation_name`:
+ The name of the operation that was retried.
+** `cause`:
+ The original cause that triggered the retry.
* `action/auto_retry_count`: Number of automatic retries with tracing
+** `action_type`:
+ The type of the action that was retried.
+** `operation_name`:
+ The name of the operation that was retried.
+** `cause`:
+ The cause for the retry.
* `action/failures_on_auto_retry_count`: Number of failures on auto retry
+** `action_type`:
+ The type of the action that was retried.
+** `operation_name`:
+ The name of the operation that was retried.
+** `cause`:
+ The cause for the retry.
+[[cancellations]]
=== Cancellations
* `cancellation/advisory_deadline_count`: Exceeded advisory deadlines by request
+** `request_type`:
+ The type of the request to which the advisory deadline applied.
+** `request_uri`:
+ The redacted URI of the request to which the advisory deadline applied (only
+ set for request_type = REST).
+** `deadline_id`:
+ The ID of the advisory deadline.
* `cancellation/cancelled_requests_count`: Number of request cancellations by
request
+** `request_type`:
+ The type of the request that was cancelled.
+** `request_uri`:
+ The redacted URI of the request that was cancelled (only set for
+ request_type = REST).
+** `cancellation_reason`:
+ The reason why the request was cancelled.
+* `cancellation/receive_timeout_count`: Number of requests that are cancelled
+ because link:config.html#receive.timeout[receive.timout] is exceeded
+** `cancellation_type`:
+ The cancellation type (graceful or forceful).
+
+[[performance]]
+=== Performance
+
+* `performance/operations`: Latency of performing operations
+** `operation_name`:
+ The operation that was performed.
+** `change_identifier`:
+ The ID of the change for which the operation was performed (format =
+ '<project>~<numeric-change-id>').
+** `trace_id`:
+ The ID of the trace if tracing was done.
+* `performance/operations_count`: Number of performed operations
+** `operation_name`:
+ The operation that was performed.
+** `trace_id`:
+ The ID of the trace if tracing was done.
+** `request`:
+ The request for which the operation was performed (format = '<request-type>
+ <redacted-request-uri>').
+* `performance/plugin_operations_count`: Number of performed operations by
+ plugin
+** `operation_name`:
+ The operation that was performed.
+** `plugin`:
+ The name of the plugin that performed the operation.
+** `trace_id`:
+ The ID of the trace if tracing was done.
+
=== Pushes
-* `receivecommits/changes`: histogram of number of changes processed
-in a single upload, split up by update type (change created/updated,
-change autoclosed).
-* `receivecommits/latency`: latency per change for processing a push,
-split up by update type (create+replace, and autoclose)
-* `receivecommits/push_latency`: total latency for processing a push,
-split up by update type (create+replace, autoclose, normal)
-* `receivecommits/timeout`: number of timeouts during push processing.
+* `receivecommits/changes`: histogram of number of changes processed in a single
+ upload
+** `type`:
+ type of push (create/replace, autoclose)
+* `receivecommits/latency_per_push`: processing delay for a processing single
+ push
+** `type`:
+ type of push (create/replace, autoclose, normal)
+* `receivecommits/latency_per_push_per_change`: Processing delay per push
+ divided by the number of changes in said push. (Only includes pushes which
+ contain changes.)
+** `type`:
+ type of push (create/replace, autoclose, normal)
+* `receivecommits/timeout`: rate of push timeouts
+* `receivecommits/ps_revision_missing`: errors due to patch set revision missing
+* `receivecommits/push_count`: number of pushes
+** `kind`:
+ The push kind (direct vs. magic).
+** `project`:
+ The name of the project for which the push is done.
+** `type`:
+ The type of the update (CREATE, UPDATE, CREATE/UPDATE, UPDATE_NONFASTFORWARD,
+ DELETE).
=== Process
@@ -55,25 +144,58 @@
* `proc/jvm/memory/object_pending_finalization_count`: Approximate number of
objects needing finalization.
* `proc/jvm/gc/count`: Number of GCs.
+** `gc_name`:
+ The name of the garbage collector.
* `proc/jvm/gc/time`: Approximate accumulated GC elapsed time.
-* `proc/jvm/memory/pool/committed/<pool name>`: Committed amount of memory for pool.
-* `proc/jvm/memory/pool/max/<pool name>`: Maximum amount of memory for pool.
-* `proc/jvm/memory/pool/used/<pool name>`: Used amount of memory for pool.
+** `gc_name`:
+ The name of the garbage collector.
+* `proc/jvm/memory/pool/committed`: Committed amount of memory for pool.
+** `pool_name`:
+ The name of the memory pool.
+* `proc/jvm/memory/pool/max`: Maximum amount of memory for pool.
+** `pool_name`:
+ The name of the memory pool.
+* `proc/jvm/memory/pool/used`: Used amount of memory for pool.
+** `pool_name`:
+ The name of the memory pool.
* `proc/jvm/thread/num_live`: Current live thread count.
* `proc/jvm/thread/num_daemon_live`: Current live daemon threads count.
-* `proc/jvm/thread/num_peak_live`: Peak live thread count since the Java virtual machine started or peak was reset.
-* `proc/jvm/thread/num_total_started`: Total number of threads created and also started since the Java virtual machine started.
-* `proc/jvm/thread/num_deadlocked_threads`: Number of threads that are deadlocked waiting for object monitors or ownable synchronizers.
- If deadlocks waiting for ownable synchronizers can be monitored depends on the capabilities of the used JVM.
+* `proc/jvm/thread/num_peak_live`: Peak live thread count since the Java virtual
+ machine started or peak was reset.
+* `proc/jvm/thread/num_total_started`: Total number of threads created and also
+ started since the Java virtual machine started.
+* `proc/jvm/thread/num_deadlocked_threads`: Number of threads that are
+ deadlocked waiting for object monitors or ownable synchronizers.
+ If deadlocks waiting for ownable synchronizers can be monitored depends on the
+ capabilities of the used JVM.
=== Caches
* `caches/memory_cached`: Memory entries.
+** `cache_name`:
+ The name of the cache.
* `caches/memory_hit_ratio`: Memory hit ratio.
+** `cache_name`:
+ The name of the cache.
* `caches/memory_eviction_count`: Memory eviction count.
+** `cache_name`:
+ The name of the cache.
* `caches/disk_cached`: Disk entries used by persistent cache.
+** `cache_name`:
+ The name of the cache.
* `caches/disk_hit_ratio`: Disk hit ratio for persistent cache.
-* `caches/refresh_count`: The number of refreshes per cache with an indicator if a reload was necessary.
+** `cache_name`:
+ The name of the cache.
+* `caches/refresh_count`: The number of refreshes per cache with an indicator if
+ a reload was necessary.
+** `cache`:
+ The name of the cache.
+** `outdated`:
+ Whether the cache entry was outdated on reload.
+* `caches/diff/timeouts`: The number of git file diff computations that resulted
+ in timeouts.
+* `caches/diff/legacy/timeouts`: The number of git file diff computations (using
+ the legacy cache) that resulted in timeouts.
Cache disk metrics are expensive to compute on larger installations and are not
computed by default. They can be enabled via the
@@ -82,65 +204,110 @@
=== Change
-* `change/submit_rule_evaluation`: Latency for evaluating submit rules on a change.
-* `change/submit_type_evaluation`: Latency for evaluating the submit type on a change.
+* `change/submit_rule_evaluation`: Latency for evaluating submit rules on a
+ change.
+* `change/submit_type_evaluation`: Latency for evaluating the submit type on a
+ change.
+* `change/post_review/draft_handling`: Total number of draft handling option
+ (KEEP, PUBLISH, PUBLISH_ALL_REVISIONS) selected by users while posting a
+ review.
+** `type`:
+ The type of the draft handling option (KEEP, PUBLISH, PUBLISH_ALL_REVISIONS).
=== Comments
-* `ported_comments/as_patchset_level`: Total number of comments ported as patchset-level comments.
-* `ported_comments/as_file_level`: Total number of comments ported as file-level comments.
-* `ported_comments/as_range_comments`: Total number of comments having line/range values in the ported patchset.
+* `ported_comments/as_patchset_level`: Total number of comments ported as
+ patchset-level comments.
+* `ported_comments/as_file_level`: Total number of comments ported as file-level
+ comments.
+* `ported_comments/as_range_comments`: Total number of comments having
+ line/range values in the ported patchset.
=== HTTP
==== Jetty
-* `http/server/jetty/connections/connections`: The current number of open connections
-* `http/server/jetty/connections/connections_total`: The total number of connections opened
-* `http/server/jetty/connections/connections_duration_max`: The max duration of a connection in ms
-* `http/server/jetty/connections/connections_duration_mean`: The mean duration of a connection in ms
-* `http/server/jetty/connections/connections_duration_stdev`: The standard deviation of the duration of a connection in ms
-* `http/server/jetty/connections/received_messages`: The total number of messages received
-* `http/server/jetty/connections/sent_messages`: The total number of messages sent
-* `http/server/jetty/connections/received_bytes`: Total number of bytes received by tracked connections
-* `http/server/jetty/connections/sent_bytes`: Total number of bytes sent by tracked connections"
+* `http/server/jetty/connections/connections`: The current number of open
+ connections
+* `http/server/jetty/connections/connections_total`: The total number of
+ connections opened
+* `http/server/jetty/connections/connections_duration_max`: The max duration of
+ a connection in ms
+* `http/server/jetty/connections/connections_duration_mean`: The mean duration
+ of a connection in ms
+* `http/server/jetty/connections/connections_duration_stdev`: The standard
+ deviation of the duration of a connection in ms
+* `http/server/jetty/connections/received_messages`: The total number of
+ messages received
+* `http/server/jetty/connections/sent_messages`: The total number of messages
+ sent
+* `http/server/jetty/connections/received_bytes`: Total number of bytes received
+ by tracked connections
+* `http/server/jetty/connections/sent_bytes`: Total number of bytes sent by
+ tracked connections
* `http/server/jetty/threadpool/active_threads`: Active threads
* `http/server/jetty/threadpool/idle_threads`: Idle threads
* `http/server/jetty/threadpool/reserved_threads`: Reserved threads
* `http/server/jetty/threadpool/max_pool_size`: Maximum thread pool size
* `http/server/jetty/threadpool/min_pool_size`: Minimum thread pool size
* `http/server/jetty/threadpool/pool_size`: Current thread pool size
-* `http/server/jetty/threadpool/queue_size`: Queued requests waiting for a thread
+* `http/server/jetty/threadpool/queue_size`: Queued requests waiting for a
+ thread
+* `http/server/jetty/threadpool/is_low_on_threads`: Whether thread pool is low
+ on threads
==== LDAP
* `ldap/login_latency`: Latency of logins.
* `ldap/user_search_latency`: Latency for searching the user account.
-* `ldap/group_search_latency`: Latency for querying the group memberships of an account.
+* `ldap/group_search_latency`: Latency for querying the group memberships of an
+ account.
* `ldap/group_expansion_latency`: Latency for expanding nested groups.
==== REST API
* `http/server/error_count`: Rate of REST API error responses.
+** `status`:
+ HTTP status code
* `http/server/success_count`: Rate of REST API success responses.
+** `status`:
+ HTTP status code
* `http/server/rest_api/count`: Rate of REST API calls by view.
+** `view`:
+ view implementation class
* `http/server/rest_api/change_id_type`: Rate of REST API calls by change ID type.
+** `change_id_type`:
+ The type of the change identifier.
* `http/server/rest_api/error_count`: Rate of REST API calls by view.
+** `view`:
+ view implementation class
+** `error_code`:
+ HTTP status code
+** `cause`:
+ The cause of the error.
* `http/server/rest_api/server_latency`: REST API call latency by view.
+** `view`:
+ view implementation class
* `http/server/rest_api/response_bytes`: Size of REST API response on network
-(may be gzip compressed) by view.
+ (may be gzip compressed) by view.
+** `view`:
+ view implementation class
* `http/server/rest_api/change_json/to_change_info_latency`: Latency for
-toChangeInfo invocations in ChangeJson.
+ toChangeInfo invocations in ChangeJson.
* `http/server/rest_api/change_json/to_change_infos_latency`: Latency for
-toChangeInfos invocations in ChangeJson.
+ toChangeInfos invocations in ChangeJson.
* `http/server/rest_api/change_json/format_query_results_latency`: Latency for
-formatQueryResults invocations in ChangeJson.
-* `http/server/rest_api/ui_actions/latency`: Latency for RestView#getDescription calls.
+ formatQueryResults invocations in ChangeJson.
+* `http/server/rest_api/ui_actions/latency`: Latency for RestView#getDescription
+ calls.
+** `view`:
+ view implementation class
=== Query
* `query/query_latency`: Successful query latency, accumulated over the life
-of the process.
+ of the process.
+** `index`: index name
=== Core Queues
@@ -159,11 +326,15 @@
Each queue provides the following metrics:
* `queue/<queue_name>/pool_size`: Current number of threads in the pool
-* `queue/<queue_name>/max_pool_size`: Maximum allowed number of threads in the pool
-* `queue/<queue_name>/active_threads`: Number of threads that are actively executing tasks
+* `queue/<queue_name>/max_pool_size`: Maximum allowed number of threads in the
+ pool
+* `queue/<queue_name>/active_threads`: Number of threads that are actively
+ executing tasks
* `queue/<queue_name>/scheduled_tasks`: Number of scheduled tasks in the queue
-* `queue/<queue_name>/total_scheduled_tasks_count`: Total number of tasks that have been scheduled
-* `queue/<queue_name>/total_completed_tasks_count`: Total number of tasks that have completed execution
+* `queue/<queue_name>/total_scheduled_tasks_count`: Total number of tasks that
+ have been scheduled
+* `queue/<queue_name>/total_completed_tasks_count`: Total number of tasks that
+ have completed execution
=== SSH sessions
@@ -175,7 +346,7 @@
* `topic/cross_project_submit`: number of cross-project topic submissions.
* `topic/cross_project_submit_completed`: number of cross-project
-topic submissions that concluded successfully.
+ topic submissions that concluded successfully.
=== JGit
@@ -192,23 +363,34 @@
* `load_success_count` : Successful cache loads for JGit block cache.
* `miss_count` : Cache misses for JGit block cache.
* `miss_ratio` : Cache miss ratio for JGit block cache.
-* `cache_used_per_repository` : Bytes of memory retained per repository for the top N repositories
-having most data in the cache. The number N of reported repositories is limited to 1000.
+* `cache_used_per_repository` : Bytes of memory retained per repository for the
+ top N repositories having most data in the cache. The number N of reported
+ repositories is limited to 1000.
+** `repository_name`: The name of the repository.
=== Git
* `git/upload-pack/request_count`: Total number of git-upload-pack requests.
+** `operation`:
+ The name of the operation (CLONE, FETCH).
* `git/upload-pack/phase_counting`: Time spent in the 'Counting...' phase.
+** `operation`:
+ The name of the operation (CLONE, FETCH).
* `git/upload-pack/phase_compressing`: Time spent in the 'Compressing...' phase.
+** `operation`:
+ The name of the operation (CLONE, FETCH).
* `git/upload-pack/phase_writing`: Time spent transferring bytes to client.
+** `operation`:
+ The name of the operation (CLONE, FETCH).
* `git/upload-pack/pack_bytes`: Distribution of sizes of packs sent to clients.
+** `operation`:
+ The name of the operation (CLONE, FETCH).
* `git/auto-merge/num_operations`: Number of auto merge operations and context.
+** `operation`:
+ The type of the operation (CACHE_LOAD, IN_MEMORY_WRITE, ON_DISK_WRITE).
* `git/auto-merge/latency`: Latency of auto merge operations and context.
-
-=== BatchUpdate
-
-* `batch_update/execute_change_ops`: BatchUpdate change update latency,
-excluding reindexing
+** `operation`:
+ The type of the operation (CACHE_LOAD, IN_MEMORY_WRITE, ON_DISK_WRITE).
=== NoteDb
@@ -218,43 +400,63 @@
* `notedb/parse_latency`: NoteDb parse latency for changes.
* `notedb/external_id_cache_load_count`: Total number of times the external ID
cache loader was called.
-* `notedb/external_id_partial_read_latency`: Latency for generating a new external ID
- cache state from a prior state.
+** `partial`:
+ Whether the reload was partial.
+* `notedb/external_id_partial_read_latency`: Latency for generating a new
+ external ID cache state from a prior state.
* `notedb/external_id_update_count`: Total number of external ID updates.
* `notedb/read_all_external_ids_latency`: Latency for reading all
-external ID's from NoteDb.
+ external ID's from NoteDb.
* `notedb/read_single_account_config_latency`: Latency for reading a single
-account config from NoteDb.
+ account config from NoteDb.
* `notedb/read_single_external_id_latency`: Latency for reading a single
-external ID from NoteDb.
+ external ID from NoteDb.
=== Permissions
-* `permissions/permission_collection/filter_latency`: Latency to filter access sections
-by user and ref.
+* `permissions/permission_collection/filter_latency`: Latency for access filter
+ computations in PermissionCollection
* `permissions/ref_filter/full_filter_count`: Rate of full ref filter operations
-* `permissions/ref_filter/skip_filter_count`: Rate of ref filter operations where
-we skip full evaluation because the user can read all refs
+* `permissions/ref_filter/skip_filter_count`: Rate of ref filter operations
+ where we skip full evaluation because the user can read all refs
=== Reviewer Suggestion
* `reviewer_suggestion/query_accounts`: Latency for querying accounts for
-reviewer suggestion.
+ reviewer suggestion.
* `reviewer_suggestion/recommend_accounts`: Latency for recommending accounts
-for reviewer suggestion.
+ for reviewer suggestion.
* `reviewer_suggestion/load_accounts`: Latency for loading accounts for
-reviewer suggestion.
+ reviewer suggestion.
* `reviewer_suggestion/query_groups`: Latency for querying groups for reviewer
-suggestion.
+ suggestion.
+* `reviewer_suggestion/filter_visibility`: Latency for removing users that can't
+ see the change
=== Repo Sequences
* `sequence/next_id_latency`: Latency of requesting IDs from repo sequences.
+** `sequence`:
+ The sequence from which IDs were retrieved.
+** `multiple`:
+ Whether more than one ID was retrieved.
=== Plugin
* `plugin/latency`: Latency for plugin invocation.
+** `plugin_name`"
+ The name of the plugin.
+** `class`:
+ The class of the plugin that was invoked.
+** `export_value`:
+ The export name under which the invoked class is registered.
* `plugin/error_count`: Number of plugin errors.
+** `plugin_name`"
+ The name of the plugin.
+** `class`:
+ The class of the plugin that was invoked.
+** `export_value`:
+ The export name under which the invoked class is registered.
=== Group
@@ -263,11 +465,19 @@
=== Replication Plugin
* `plugins/replication/replication_latency`: Time spent pushing to remote
-destination.
+ destination.
+** `destination`: The destination of the replication.
* `plugins/replication/replication_delay`: Time spent waiting before pushing to
-remote destination.
+ remote destination.
+** `destination`: The destination of the replication.
* `plugins/replication/replication_retries`: Number of retries when pushing to
-remote destination.
+ remote destination.
+** `destination`: The destination of the replication.
+* `plugins/replication/latency_slower_than_threshold`: latency for project to
+ destination, where latency was slower than threshold
+** `slow_threshold`: The threshold.
+** `project`: The name of the project.
+** `destination`: The destination of the replication.
=== License
diff --git a/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt b/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt
new file mode 100644
index 0000000..1fb4b97
--- /dev/null
+++ b/Documentation/pgm-ChangeExternalIdCaseSensitivity.txt
@@ -0,0 +1,71 @@
+= ChangeExternalIdCaseSensitivity
+
+== NAME
+ChangeExternalIdCaseSensitivity - Convert `username` and `gerrit`
+external IDs to be handled case insensitively
+
+== SYNOPSIS
+[verse]
+--
+_java_ -jar gerrit.war _ChangeExternalIdCaseSensitivity_
+ -d <SITE_PATH>
+ [--batch]
+ [--dryrun]
+--
+
+== DESCRIPTION
+Convert `username` and `gerrit` external IDs to be handled case
+insensitively or case sensitively. This is done by recomputing
+the name of the note from the sha1 sum of the all lowercase
+external ID key or of the key with its original capitalization
+respectively.
+
+The tool uses the `auth.userNameCaseInsensitive` option to determine,
+whether the migration should be performed to case insensitive or case sensitive
+usernames, i.e. if the option is set to `false`, migration will be performed to
+make external IDs case insensitive and if set to `true` to case sensitive.
+
+== OPTIONS
+
+-d::
+--site-path::
+ Path of the Gerrit site
+
+--batch::
+ No user interaction is required. The tool won't ask for confirmation before migrating.
+
+--dryrun::
+ Whether to perform the conversion without persisting it.
+
+== CONTEXT
+This command can only be run offline with direct access to the server's
+site.
+
+== EXAMPLES
+To convert the external IDs to be case insensitive:
+
+----
+ $ git config -f $SITE/etc/gerrit.config --get auth.userNameCaseInsensitive
+ > false
+ $ java -jar gerrit.war ChangeExternalIdCaseSensitivity -d site_path
+----
+
+To convert the external IDs to be case sensitive again:
+
+----
+ $ git config -f $SITE/etc/gerrit.config --get auth.userNameCaseInsensitive
+ > true
+ $ java -jar gerrit.war ChangeExternalIdCaseSensitivity -d site_path
+----
+
+
+== SEE ALSO
+
+* Configuration parameter link:config-gerrit.html#auth.userNameCaseInsensitive[auth.userNameCaseInsensitive]
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/pgm-index.txt b/Documentation/pgm-index.txt
index dde0231..8f4cbda 100644
--- a/Documentation/pgm-index.txt
+++ b/Documentation/pgm-index.txt
@@ -38,6 +38,9 @@
link:pgm-LocalUsernamesToLowerCase.html[LocalUsernamesToLowerCase]::
Convert the local username of every account to lower case.
+link:pgm-ChangeExternalIdCaseSensitivity.html[ChangeExternalIdCaseSensitivity]::
+ Convert external IDs to be case insensitive.
+
link:pgm-MigrateAccountPatchReviewDb.html[MigrateAccountPatchReviewDb]::
Migrates AccountPatchReviewDb from one database backend to another.
diff --git a/Documentation/rest-api-accounts.txt b/Documentation/rest-api-accounts.txt
index 0caebfc..ae0c0a6 100644
--- a/Documentation/rest-api-accounts.txt
+++ b/Documentation/rest-api-accounts.txt
@@ -1343,6 +1343,7 @@
"time_format": "HHMM_12",
"size_bar_in_change_table": true,
"disable_keyboard_shortcuts": true,
+ "disable_token_highlighting": true,
"diff_view": "SIDE_BY_SIDE",
"mute_common_path_prefixes": true,
"my": [
@@ -1394,6 +1395,7 @@
"diff_view": "SIDE_BY_SIDE",
"publish_comments_on_push": true,
"disable_keyboard_shortcuts": true,
+ "disable_token_highlighting": true,
"work_in_progress_by_default": true,
"mute_common_path_prefixes": true,
"my": [
@@ -1779,7 +1781,16 @@
Only external ids belonging to the caller may be deleted. Users that have
link:access-control.html#capability_modifyAccount[Modify Account] can delete
-external ids that belong to other accounts.
+external ids that belong to other accounts. External ids in the 'username:'
+scheme can only be deleted by users that have
+link:access-control.html#capability_administrateServer[Administrate Server]
+or both
+link:access-control.html#capability_maintainServer[Maintain Server] and
+link:access-control.html#capability__modifyAccount[Modify Account]
+since the user may not be able to login anymore, after the removal of the
+external id with scheme 'username:'. Users cannot delete their own external id
+with scheme 'username:' in order to prevent they can lock themselves out
+since they may not be able to login anymore.
.Request
----
@@ -2001,7 +2012,7 @@
--
Star a change with the default label. Changes starred with the default
-label are returned for the search query `is:starred` or `starredby:USER`
+label are returned for the search query `is:starred` or `has:star`
and automatically notify the user whenever updates are made to the
change.
@@ -2033,131 +2044,6 @@
HTTP/1.1 204 No Content
----
-[[star-endpoints]]
-== Star Endpoints
-
-[[get-starred-changes]]
-=== Get Starred Changes
---
-'GET /accounts/link:#account-id[\{account-id\}]/stars.changes'
---
-
-Gets the changes that were starred with any label by the identified
-user account. This URL endpoint is functionally identical to the
-changes query `GET /changes/?q=has:stars`. The result is a list of
-link:rest-api-changes.html#change-info[ChangeInfo] entities.
-
-.Request
-----
- GET /a/accounts/self/stars.changes
-----
-
-.Response
-----
- HTTP/1.1 200 OK
- Content-Disposition: attachment
- Content-Type: application/json; charset=UTF-8
-
- )]}'
- [
- {
- "id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
- "project": "myProject",
- "branch": "master",
- "change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
- "subject": "Implementing Feature X",
- "status": "NEW",
- "created": "2013-02-01 09:59:32.126000000",
- "updated": "2013-02-21 11:16:36.775000000",
- "stars": [
- "ignore",
- "risky"
- ],
- "mergeable": true,
- "submittable": false,
- "insertions": 145,
- "deletions": 12,
- "_number": 3965,
- "owner": {
- "name": "John Doe"
- }
- }
- ]
-----
-
-[[get-stars]]
-=== Get Star Labels From Change
---
-'GET /accounts/link:#account-id[\{account-id\}]/stars.changes/link:rest-api-changes.html#change-id[\{change-id\}]'
---
-
-Get star labels from a change.
-
-.Request
-----
- GET /a/accounts/self/stars.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
-----
-
-As response the star labels that the user applied on the change are
-returned. The labels are lexicographically sorted.
-
-.Response
-----
- HTTP/1.1 200 OK
- Content-Disposition: attachment
- Content-Type: application/json; charset=UTF-8
-
- )]}'
- [
- "blue",
- "green",
- "red"
- ]
-----
-
-[[set-stars]]
-=== Update Star Labels On Change
---
-'POST /accounts/link:#account-id[\{account-id\}]/stars.changes/link:rest-api-changes.html#change-id[\{change-id\}]'
---
-
-Update star labels on a change. The star labels to be added/removed
-must be specified in the request body as link:#stars-input[StarsInput]
-entity. Starred changes are returned for the search query `has:stars`.
-
-.Request
-----
- POST /a/accounts/self/stars.changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0
- Content-Type: application/json; charset=UTF-8
-
- {
- "add": [
- "blue",
- "red"
- ],
- "remove": [
- "yellow"
- ]
- }
-----
-
-As response the star labels that the user applied on the change are
-returned. The labels are lexicographically sorted.
-
-.Response
-----
- HTTP/1.1 200 OK
- Content-Disposition: attachment
- Content-Type: application/json; charset=UTF-8
-
- )]}'
- [
- "blue",
- "green",
- "red"
- ]
-----
-
[[ids]]
== IDs
@@ -2820,6 +2706,8 @@
Allowed values are `AUTO_MERGE` and `FIRST_PARENT`.
|`disable_keyboard_shortcuts` |not set if `false`|
Whether to disable all keyboard shortcuts.
+|`disable_token_highlighting` [not set if `false`]
+Whether to disable token highlighting on hover.
|`publish_comments_on_push` |not set if `false`|
Whether to link:user-upload.html#publish-comments[publish draft comments] on
push by default.
@@ -2917,18 +2805,6 @@
|`valid` ||Whether the SSH key is valid.
|=============================
-[[stars-input]]
-=== StarsInput
-The `StarsInput` entity contains star labels that should be added to
-or removed from a change.
-
-[options="header",cols="1,^1,5"]
-|========================
-|Field Name ||Description
-|`add` |optional|List of labels to add to the change.
-|`remove` |optional|List of labels to remove from the change.
-|========================
-
[[username-input]]
=== UsernameInput
The `UsernameInput` entity contains information for setting the
diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt
index b376a74..d83ef0e 100644
--- a/Documentation/rest-api-changes.txt
+++ b/Documentation/rest-api-changes.txt
@@ -600,8 +600,9 @@
----
As a response, two link:#change-info[ChangeInfo] entities are returned
-that describe information added and removed from the `old` change state.
-Only fields that differ between the change's two states are returned.
+that describe information added and removed from the `old` change state, and
+the two link:#change-info[ChangeInfo] entities that generated the diff are
+returned. Only fields that differ between the change's two states are returned.
.Response
----
@@ -625,9 +626,55 @@
"topic": "new-topic"
},
"removed": {
- "updated": "2013-02-20 12:05:34.111000000",
+ "updated": "2013-02-01 09:59:32.126000000",
"topic": "old-topic"
- }
+ },
+ "old_change_info": {
+ "id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
+ "project": "myProject",
+ "branch": "master",
+ "attention_set": [],
+ "change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
+ "subject": "Implementing Feature X",
+ "status": "NEW",
+ "topic": "old-topic",
+ "created": "2013-02-01 09:59:32.126000000",
+ "updated": "2013-02-01 09:59:32.126000000",
+ "mergeable": true,
+ "insertions": 34,
+ "deletions": 101,
+ "_number": 3965,
+ "owner": {
+ "name": "John Doe"
+ }
+ },
+ "new_change_info": {
+ "id": "myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940",
+ "project": "myProject",
+ "branch": "master",
+ "attention_set": [
+ {
+ "account": {
+ "name": "John Doe"
+ },
+ "last_update": "2013-02-21 11:16:36.775000000",
+ "reason": "reviewer or cc replied"
+ }
+ ],
+ "change_id": "I8473b95934b5732ac55d26311a706c9c2bde9940",
+ "subject": "Implementing Feature X",
+ "status": "NEW",
+ "topic": "new-topic",
+ "created": "2013-02-01 09:59:32.126000000",
+ "updated": "2013-02-21 11:16:36.775000000",
+ "mergeable": true,
+ "insertions": 34,
+ "deletions": 101,
+ "_number": 3965,
+ "owner": {
+ "name": "John Doe"
+ }
+ },
}
----
@@ -2561,42 +2608,6 @@
PUT /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/unignore HTTP/1.0
----
-[[mark-as-reviewed]]
-=== Mark as Reviewed
---
-'PUT /changes/link:#change-id[\{change-id\}]/reviewed'
---
-
-Marks a change as reviewed.
-
-This allows users to "de-highlight" changes in their dashboard until a new
-patch set is uploaded.
-
-This differs from the link:#ignore[ignore] endpoint, which will mute
-emails and hide the change from dashboard completely until it is
-link:#unignore[unignored] again.
-
-
-.Request
-----
- PUT /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/reviewed HTTP/1.0
-----
-
-[[mark-as-unreviewed]]
-=== Mark as Unreviewed
---
-'PUT /changes/link:#change-id[\{change-id\}]/unreviewed'
---
-
-Marks a change as unreviewed.
-
-This allows users to "highlight" changes in their dashboard
-
-.Request
-----
- PUT /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/unreviewed HTTP/1.0
-----
-
[[get-hashtags]]
=== Get Hashtags
--
@@ -3264,6 +3275,8 @@
* are visible to the calling user
* are not already reviewer on the change
* don't own the change
+* are not service users (unless
+ link:config.html#suggest.skipServiceUsers[skipServiceUsers] is set to `false`)
Groups can be excluded from the results by specifying the 'exclude-groups'
request parameter:
@@ -6512,7 +6525,9 @@
|`unresolved_comment_count` |optional|
Number of unresolved inline comment threads across all patch sets. Not set if
the current change index doesn't have the data.
-|`_number` ||The legacy numeric ID of the change.
+|`_number` ||
+The numeric ID of the change. (The underscore is just a relict of a prior
+attempt to deprecate the numeric ID.)
|`owner` ||
The owner of the change as an link:rest-api-accounts.html#account-info[
AccountInfo] entity.
@@ -6520,6 +6535,9 @@
Actions the caller might be able to perform on this revision. The
information is a map of view name to link:#action-info[ActionInfo]
entities.
+|`submit_records` ||
+List of the link:rest-api-changes.html#submit-record-info[SubmitRecordInfo]
+containing the submit records for the change at the latest patchset.
|`requirements` |optional|
List of the link:rest-api-changes.html#requirement[requirements] to be met before this change
can be submitted. This field is deprecated in favour of `submit_requirements`.
@@ -8161,6 +8179,37 @@
the failure of the rule predicate.
|===========================
+[[submit-record-info]]
+=== SubmitRecordInfo
+The `SubmitRecordInfo` entity describes results from a submit_rule.
+
+[options="header",cols="1,^1,5"]
+|===========================
+|Field Name ||Description
+|`rule_name`||
+The name of the submit rule that created this submit record. The submit rule is
+specified in the form of "$plugin~$rule" where `$plugin` is the plugin name
+and `$rule` is the name of the class that implemented the submit rule.
+|`status`||
+`OK`, the change can be submitted. +
+`NOT_READY`, additional labels are required before submit. +
+`CLOSED`, closed changes cannot be submitted. +
+`FORCED`, the change was submitted bypassing the submit rule. +
+`RULE_ERROR`, rule code failed with an error.
+|`labels`|optional|
+A list of labels, each containing the following fields. +
+ * `label`: the label name. +
+ * `status`: the label status: {`OK`, `REJECT`, `MAY`, `NEED`, `IMPOSSIBLE`}. +
+ * `appliedBy`: the link:rest-api-accounts.html#account-info[AccountInfo]
+ that applied the vote to the label.
+|`requirements`|optional|
+List of the link:rest-api-changes.html#requirement[requirements] to be met
+before this change can be submitted.
+|`error_message`|optional|
+When status is RULE_ERROR this message provides some text describing
+the failure of the rule predicate.
+|===========================
+
[[submit-requirement-expression-info]]
=== SubmitRequirementExpressionInfo
The `SubmitRequirementExpressionInfo` describes the result of evaluating a
@@ -8198,6 +8247,10 @@
|`status`||
Status describing the result of evaluating the submit requirement. The status
is one of (`SATISFIED`, `UNSATISFIED`, `OVERRIDDEN`, `NOT_APPLICABLE`).
+|`is_legacy`||
+If true, this submit requirement result was created from a legacy
+link:#submit-record[SubmitRecord]. Otherwise, it was created by evaluating a
+submit requirement.
|`applicability_expression_result`|optional|
A link:#submit-requirement-expression-info[SubmitRequirementExpressionInfo]
containing the result of evaluating the applicability expression. Not set if the
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index eb38434..92c6dbf 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -2561,6 +2561,9 @@
Retrieves the branches and tags in which a change is included. As result
an link:rest-api-changes.html#included-in-info[IncludedInInfo] entity is returned.
+Branches that are not visible to the calling user according to the project's
+read permissions are filtered out from the result.
+
.Request
----
GET /projects/work%2Fmy-project/commits/a8a477efffbbf3b44169bb9a1d3a334cbbd9aa96/in HTTP/1.0
diff --git a/Documentation/user-request-cancellation-and-deadlines.txt b/Documentation/user-request-cancellation-and-deadlines.txt
new file mode 100644
index 0000000..b368d6a
--- /dev/null
+++ b/Documentation/user-request-cancellation-and-deadlines.txt
@@ -0,0 +1,184 @@
+:linkattrs:
+= Request Cancellation and Deadlines
+
+[[motivation]]
+== Motivation
+
+Protect the Gerrit service by aborting requests that were cancelled or for which
+the deadline has exceeded. If these requests are not aborted, it can happen that
+too many of these requests are accumulated so that the server runs out of
+resources (e.g. threads).
+
+[[request-cancellation]]
+== Request Cancellation
+
+If a user cancels a request by disconnecting, ideally Gerrit should detect this
+and abort the request execution to avoid doing unnecessary work. If nobody is
+waiting for the response, Gerrit shouldn't spend resources to compute it.
+
+Detecting cancelled requests is not easily possible with all protocols that a
+client may use. At the moment Gerrit only detects request cancellations for git
+pushes, but not for other request types (in particular cancelled requests are
+not detected for REST calls over HTTP, SSH commands and git clone/fetch).
+
+[[server-side-deadlines]]
+== Server-side deadlines
+
+To limit the maximal execution time for requests, administrators can [configure
+server-side deadlines](config-gerrit.html#deadline.id). If a server-side
+deadline is exceeded by a matching request, the request is automatically
+aborted. In this case the client gets a proper error message informing the user
+about the exceeded deadline.
+
+Clients may override server-side deadlines by setting a
+[deadline](#client-provided-deadline) on the request. This means, if a request
+fails due to an exceeded server-side deadline, the client may repeat the request
+with a higher deadline or no deadline (deadline = 0) to get unblocked.
+
+Server-side deadlines are meant to protect the Gerrit service against resource
+exhaustion due to performence issues with a particular request. E.g. imagine a
+situation where requests for a certain REST endpoint are very slow. If more and
+more of such requests get stuck and are not being aborted, the Gerrit service
+may run out of threads, causing an outage for the entire Gerrit service.
+Server-side deadlines may prevent this because the slow requests get aborted
+after the deadline is exceeded, and hence the server resources are freed up.
+
+In some cases server-side deadlines may also lead to a better user experience,
+as it's better to tell the user that there is a performance issue, that prevents
+the execution of the request, than letting them wait indefinitely.
+
+Finally server-side deadlines can help ops engineers to detect performance
+issues more reliably and more quicky. For this alerts may be setup that are
+based on the [cancellation metrics](metrics.html#cancellations).
+
+[[receive-timeout]]
+=== Receive Timeout
+
+For git pushes it is possible to configure a [hard
+timeout](config-gerrit.html#receive.timeout). In contrast to server-side
+deadlines, this timeout is not overridable by [client-provided
+deadlines](#client-provided-deadlines).
+
+[[client-provided-deadlines]]
+== Client-provided deadlines
+
+Clients can set a deadline on requests to limit the maximal execution time that
+they are willing to wait for a response. If the request doesn't finish within
+this deadline the request is aborted and the client receives an error, with a
+message telling them that the deadline has been exceeded.
+
+How to set a deadline on a request depends on the request type:
+
+[options="header",cols="1,6"]
+|=======================
+|Request Type |How to set a deadline?
+|REST over HTTP |Set the [X-Gerrit-Deadline header](rest-api.html#deadline).
+|SSH command |Set the [deadline option](cmd-index.html#deadline).
+|git push |Set the [deadline push option](user-upload.html#deadline).
+|git clone/fetch|Not supported.
+|=======================
+
+[[override-server-side-deadline]]
+=== Override server-side deadline
+
+By setting a deadline on a request it is possible to override any [server-side
+deadline](#server-side-deadline), e.g. in order to increase it. Setting the
+deadline to `0` disables any server-side deadline. This allows clients to get
+unblocked if a request has previously failed due to an exceeded deadline.
+
+[NOTE]
+It is stronly discouraged for clients to permanently override [server-side
+deadlines](#server-side-deadlines] with a higher deadline or to permanently
+disable them by always setting the deadline to `0`. If this becomes necessary
+the caller should get in touch with the Gerrit administrators to increase the
+server-side deadlines or resolve the performance issue in another way.
+
+[NOTE]
+It's not possible for clients to override the [receive
+timeout](#receive-timeout) that is enforced on git push.
+
+[[faqs]]
+== FAQs
+
+[[deadline-exceeded-what-to-do]]
+=== My request failed due to an execeeded deadline, what can I do?
+
+To get unblocked, you may repeat the request with deadlines disabled. To do this
+set the deadline to `0` on the request as explained
+[above](#override-server-side-deadline).
+
+If doing this becomes required frequently, please get in touch with the Gerrit
+administrators in order to investigate the performance issue and increase the
+server-side deadline if necessary.
+
+[NOTE]
+Setting deadlines for requests that are done from the Gerrit web UI is not
+possible. If exceeded deadlines occur frequently here, please get in touch with
+the Gerrit administrators in order to investigate the performance issue.
+
+[[push-fails-due-to-exceeded-deadline-but-cannot-be-overridden]]
+=== My git push fails due to an exceeded deadline and I cannot override the deadline, what can I do?
+
+As explained [above](#receive-timeout) a configured receive timeout cannot be
+overridden by clients. If pushes fail due to this timeout, get in touch with the
+Gerrit administrators in order to investigate the performance issue and increase
+the receive timeout if necessary.
+
+[[when-are-requests-aborted]]
+=== How quickly does a request get aborted when it is cancelled or a deadline is exceeded?
+
+In order to know if a request should be aborted, Gerrit needs to explicitly
+check whether the request is cancelled or whether a deadline is exceeded.
+Gerrit does this check at the beginning and end of all performance critical
+steps and sub-steps. This means, the request is only aborted the next time such
+a step starts or finishes, which can also be never (e.g. if the request is stuck
+inside of a step).
+
+[NOTE]
+Technically the check whether a request should be aborted is done whenever the
+execution time of an operation or sub-step is captured, either by a timer
+metric or a `TraceTimer` ('TraceTimer` is the class that logs the execution time
+when the request is being [traced](user-request-tracing.html)).
+
+[[how-are-requests-aborted]]
+=== How does Gerrit abort requests?
+
+The exact response that is returned to the client depends on the request type
+and the cancellation reason:
+
+[options="header",cols="1,3,3"]
+|=======================
+|Request Type |Cancellation Reason|Response
+|REST over HTTP |Client Disconnected|The response is '499 Client Closed Request'.
+| |Server-side deadline exceeded|The response is '408 Server Deadline Exceeded'.
+| |Client-provided deadline exceeded|The response is '408 Client Provided Deadline Exceeded'.
+|SSH command |Client Disconnected|The error message is 'Client Closed Request'.
+| |Server-side deadline exceeded|The error message is 'Server Deadline Exceeded'.
+| |Client-provided deadline exceeded|The error message is 'Client Provided Deadline Exceeded'.
+|git push |Client Disconnected|The error status is 'Client Closed Request'.
+| |Server-side deadline exceeded|The error status is 'Server Deadline Exceeded'.
+| |Client-provided deadline exceeded|The error status is 'Client Provided Deadline Exceeded'.
+|git clone/fetch|Not supported.
+|=======================
+
+This means clients always get a proper error message telling the user why the
+request has been aborted.
+
+Errors due to aborted requests are usually not counted as internal server errors,
+but the [cancellation metrics](metrics.html#cancellations) may be used to setup
+alerting for performance issues.
+
+[NOTE]
+During a request, cancellations can occur at any time. This means for non-atomic
+operations, it can happen that the operation is cancelled after some steps have
+already been successfully performed and before all steps have been executed,
+potentially leaving behind an inconsistent state (same as when a request fails
+due to an error). However for important steps, such a NoteDb updates that span
+multiple repositories, Gerrit ensures that they are not torn by cancellations.
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-request-tracing.txt b/Documentation/user-request-tracing.txt
index e684b85..303242df 100644
--- a/Documentation/user-request-tracing.txt
+++ b/Documentation/user-request-tracing.txt
@@ -148,3 +148,10 @@
* permission checks (e.g. which rule is responsible for a deny)
* timer metrics
* all other logs
+
+GERRIT
+------
+Part of link:index.html[Gerrit Code Review]
+
+SEARCHBOX
+---------
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index a9779b1..3977278 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -321,7 +321,7 @@
+
Matches any change touching file at 'PATH'. By default exact path
matching is used, but regular expressions can be enabled by starting
-with `^`. For example, to match all XML files use `file:^.*\.xml$`.
+with `^`. For example, to match all XML files use `file:"^.*\.xml$"`.
The link:http://www.brics.dk/automaton/[dk.brics.automaton library,role=external,window=_blank]
is used for the evaluation of such patterns.
+
@@ -331,15 +331,15 @@
files, use `file:^.*\.java`.
+
The entire regular expression pattern, including the `^` character,
-should be double quoted when using more complex construction (like
-ones using a bracket expression). For example, to match all XML
+should be double quoted. For example, to match all XML
files named like 'name1.xml', 'name2.xml', and 'name3.xml' use
`file:"^name[1-3].xml"`.
+
Slash ('/') is used path separator.
+
-More examples:
-* `-file:^path/.*` - changes that do not modify files from `path/`,
+*More examples:*
+
+* `-file:^path/.*` - changes that do not modify files from `path/`.
* `file:{^~(path/.*)}` - changes that modify files not from `path/` (but may
contain files from `path/`).
@@ -406,6 +406,8 @@
+
'star:star' is the same as 'has:star' and 'is:starred'.
+Only "ignore" and "star" are supported labels.
+
[[has]]
has:draft::
+
@@ -417,11 +419,6 @@
Same as 'is:starred' and 'star:star', true if the change has been
starred by the current user with the default label.
-[[has-stars]]
-has:stars::
-+
-True if the change has been starred by the current user with any label.
-
has:edit::
+
True if the change has inline edit created by the current user.
@@ -430,6 +427,11 @@
+
True if the change has unresolved comments.
+has:attention::
++
+True if the change has attention by the current user.
+
+
[[is]]
is:assigned::
+
@@ -445,6 +447,10 @@
+
True if the change does not have an assignee.
+is:attention::
++
+True if the change has attention by the current user.
+
is:watched::
+
True if this change matches one of the current user's watch filters,
@@ -530,6 +536,16 @@
+
True if the change is a merge commit.
+[[cherrypick]]
+is:cherrypick::
++
+True if the change is a cherrypick of an another change.
+
+This is limited to changes which are cherrypicked using REST API
+or WebUI only. It is not able to identify changes which are
+cherry-picked locally using the git cherry-pick command and then
+pushed to Gerrit.
+
[[status]]
status:open, status:pending, status:new::
+
@@ -588,14 +604,17 @@
author:'AUTHOR'::
+
Changes where 'AUTHOR' is the author of the current patch set. 'AUTHOR' may be
-the author's exact email address, or part of the name or email address.
+the author's exact email address, or part of the name or email address. The
+special case of `author:self` will find changes authored by the caller.
[[committer]]
committer:'COMMITTER'::
+
Changes where 'COMMITTER' is the committer of the current patch set.
'COMMITTER' may be the committer's exact email address, or part of the name or
-email address.
+email address. The special case of `committer:self` will find changes committed
+by the caller.
+
[[submittable]]
submittable:'SUBMIT_STATUS'::
@@ -606,6 +625,22 @@
only applies to the top-level status; individual label statuses can be
searched link:#labels[by label].
+[[rule]]
+rule:'SUBMIT_RULE_NAME'::
++
+Changes where 'SUBMIT_RULE_NAME' returns a submit record with status in {OK,
+FORCED}. This means that the submit rule has passed and is not blocking the
+change submission. 'SUBMIT_RULE_NAME' should be in the form of
+'$plugin_name~$rule_name'. For gerrit core rules, 'SUBMIT_RULE_NAME' should
+be in the form of '$rule_name' (example: `DefaultSubmitRule`), or
+'gerrit~$rule_name' (example: `gerrit~DefaultSubmitRule`).
+
+rule:'SUBMIT_RULE_NAME'='STATUS'::
++
+Changes where 'SUBMIT_RULE_NAME' returns a submit record with status equals to
+'STATUS'. The status can be any of the statuses that are documented for the
+`status` field of link:rest-api-changes.html#submit-record[SubmitRecord].
+
[[unresolved]]
unresolved:'RELATION''NUMBER'::
+
@@ -702,6 +737,10 @@
to one of the fields in the
link:rest-api-changes.html#submit-record[SubmitRecord] REST API entity.
+`label:Code-Review\<=-1`::
++
+Matches changes with either a -1, -2, or any lower score.
+
`label:Code-Review=MAX`::
+
Matches changes with label voted with the highest possible score.
@@ -738,15 +777,20 @@
The special "owner" parameter corresponds to the change owner. Matches
all changes that have a +2 vote from the change owner.
+`label:Code-Review=+2,user=non_uploader`::
+`label:Code-Review=ok,user=non_uploader`::
+`label:Code-Review=+2,non_uploader`::
+`label:Code-Review=ok,non_uploader`::
++
+The special "non_uploader" parameter corresponds to any user who's not the
+uploader of the latest patchset. Matches all changes that have a +2 vote from
+a non upoader.
+
`label:Code-Review=+1,group=ldap/linux.workflow`::
+
Matches changes with a +1 code review where the reviewer is in the
ldap/linux.workflow group.
-`label:Code-Review\<=-1`::
-+
-Matches changes with either a -1, -2, or any lower score.
-
`is:open label:Code-Review+2 label:Verified+1 NOT label:Verified-1 NOT label:Code-Review-2`::
`is:open label:Code-Review=ok label:Verified=ok`::
+
@@ -785,24 +829,6 @@
Magical internal flag to prove the current user has access to read
the change. This flag is always added to any query.
-starredby:'USER'::
-+
-Matches changes that have been starred by 'USER' with the default label.
-The special case `starredby:self` applies to the caller.
-
-watchedby:'USER'::
-+
-Matches changes that 'USER' has configured watch filters for.
-The special case `watchedby:self` applies to the caller.
-
-draftby:'USER'::
-+
-Matches changes that 'USER' has left unpublished draft comments on.
-Since the drafts are unpublished, it is not possible to see the
-draft text, or even how many drafts there are. The special case
-of `draftby:self` will find changes where the caller has created
-a draft comment.
-
[[limit]]
limit:'CNT'::
+
diff --git a/WORKSPACE b/WORKSPACE
index 5c38224..93cae7d 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -922,7 +922,6 @@
yarn_install(
name = "npm",
- data = ["//:twinkie.patch"],
frozen_lockfile = False,
package_json = "//:package.json",
package_path = "",
diff --git a/contrib/ui-api-proxy.go b/contrib/ui-api-proxy.go
deleted file mode 100644
index 1ae1c1a..0000000
--- a/contrib/ui-api-proxy.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// ui-api-proxy is a reverse http proxy that allows the UI to be served from
-// a different host than the API. This allows testing new UI features served
-// from localhost but using live production data.
-//
-// Run the binary, download & install the Go tools available at
-// http://golang.org/doc/install . To run, execute `go run ui-api-proxy.go`.
-// For a description of the available flags, execute
-// `go run ui-api-proxy.go --help`.
-package main
-
-import (
- "flag"
- "fmt"
- "log"
- "net"
- "net/http"
- "net/http/httputil"
- "net/url"
- "strings"
- "time"
-)
-
-var (
- ui = flag.String("ui", "http://localhost:8080", "host to which ui requests will be forwarded")
- api = flag.String("api", "https://gerrit-review.googlesource.com", "host to which api requests will be forwarded")
- port = flag.Int("port", 0, "port on which to run this server")
-)
-
-func main() {
- flag.Parse()
-
- uiURL, err := url.Parse(*ui)
- if err != nil {
- log.Fatalf("proxy: parsing ui addr %q failed: %v\n", *ui, err)
- }
- apiURL, err := url.Parse(*api)
- if err != nil {
- log.Fatalf("proxy: parsing api addr %q failed: %v\n", *api, err)
- }
-
- l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%v", *port))
- if err != nil {
- log.Fatalln("proxy: listen failed: ", err)
- }
- defer l.Close()
- fmt.Printf("OK\nListening on http://%v/\n", l.Addr())
-
- err = http.Serve(l, &httputil.ReverseProxy{
- FlushInterval: 500 * time.Millisecond,
- Director: func(r *http.Request) {
- if strings.HasPrefix(r.URL.Path, "/changes/") || strings.HasPrefix(r.URL.Path, "/projects/") {
- r.URL.Scheme, r.URL.Host = apiURL.Scheme, apiURL.Host
- } else {
- r.URL.Scheme, r.URL.Host = uiURL.Scheme, uiURL.Host
- }
- if r.URL.Scheme == "" {
- r.URL.Scheme = "http"
- }
- r.Host, r.URL.Opaque, r.URL.RawQuery = r.URL.Host, r.RequestURI, ""
- },
- })
- if err != nil {
- log.Fatalln("proxy: serve failed: ", err)
- }
-}
diff --git a/java/com/google/gerrit/acceptance/AccountCreator.java b/java/com/google/gerrit/acceptance/AccountCreator.java
index aa13339..c67991d 100644
--- a/java/com/google/gerrit/acceptance/AccountCreator.java
+++ b/java/com/google/gerrit/acceptance/AccountCreator.java
@@ -29,6 +29,7 @@
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.ServiceUserClassifier;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.group.db.GroupDelta;
import com.google.gerrit.server.group.db.GroupsUpdate;
import com.google.gerrit.server.notedb.Sequences;
@@ -52,18 +53,21 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final GroupCache groupCache;
private final Provider<GroupsUpdate> groupsUpdateProvider;
+ private final ExternalIdFactory externalIdFactory;
@Inject
AccountCreator(
Sequences sequences,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
GroupCache groupCache,
- @ServerInitiated Provider<GroupsUpdate> groupsUpdateProvider) {
+ @ServerInitiated Provider<GroupsUpdate> groupsUpdateProvider,
+ ExternalIdFactory externalIdFactory) {
accounts = new HashMap<>();
this.sequences = sequences;
this.accountsUpdateProvider = accountsUpdateProvider;
this.groupCache = groupCache;
this.groupsUpdateProvider = groupsUpdateProvider;
+ this.externalIdFactory = externalIdFactory;
}
public synchronized TestAccount create(
@@ -84,11 +88,11 @@
String httpPass = null;
if (username != null) {
httpPass = "http-pass";
- extIds.add(ExternalId.createUsername(username, id, httpPass));
+ extIds.add(externalIdFactory.createUsername(username, id, httpPass));
}
if (email != null) {
- extIds.add(ExternalId.createEmail(id, email));
+ extIds.add(externalIdFactory.createEmail(id, email));
}
accountsUpdateProvider
diff --git a/java/com/google/gerrit/acceptance/FakeSubmitRule.java b/java/com/google/gerrit/acceptance/FakeSubmitRule.java
new file mode 100644
index 0000000..d53456f
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/FakeSubmitRule.java
@@ -0,0 +1,43 @@
+// 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;
+
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.entities.SubmitRecord.Status;
+import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.rules.SubmitRule;
+import com.google.inject.AbstractModule;
+import com.google.inject.Singleton;
+import java.util.Optional;
+
+/** Fake submit rule that returns OK if the change contains one or more hashtags. */
+@Singleton
+public class FakeSubmitRule implements SubmitRule {
+ public static class Module extends AbstractModule {
+ @Override
+ public void configure() {
+ bind(SubmitRule.class).annotatedWith(Exports.named("Fake")).to(FakeSubmitRule.class);
+ }
+ }
+
+ @Override
+ public Optional<SubmitRecord> evaluate(ChangeData cd) {
+ SubmitRecord record = new SubmitRecord();
+ record.status = cd.hashtags().isEmpty() ? Status.NOT_READY : Status.OK;
+ record.ruleName = FakeSubmitRule.class.getSimpleName();
+ return Optional.of(record);
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/GerritServer.java b/java/com/google/gerrit/acceptance/GerritServer.java
index 9732d2c..4d87f4d 100644
--- a/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/java/com/google/gerrit/acceptance/GerritServer.java
@@ -293,7 +293,6 @@
* @param baseConfig default config values; merged with config from {@code desc} and then written
* into {@code site/etc/gerrit.config}.
* @param site temp directory where site will live.
- * @throws Exception
*/
public static void init(Description desc, Config baseConfig, Path site) throws Exception {
checkArgument(!desc.memory(), "can't initialize site path for in-memory test: %s", desc);
@@ -347,7 +346,6 @@
* @param testSysModule additional Guice module to use.
* @param testSshModule additional Guice module to use.
* @return started server.
- * @throws Exception
*/
public static GerritServer initAndStart(
TemporaryFolder temporaryFolder,
@@ -384,7 +382,6 @@
* @param additionalArgs additional command-line arguments for the daemon program; only allowed if
* the test is not in-memory.
* @return started server.
- * @throws Exception
*/
public static GerritServer start(
Description desc,
diff --git a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index e4b0eea..373246a 100644
--- a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -21,6 +21,8 @@
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
+import com.google.gerrit.server.config.FileBasedAllProjectsConfigProvider;
import com.google.gerrit.server.config.FileBasedGlobalPluginConfigProvider;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GlobalPluginConfigProvider;
@@ -57,6 +59,7 @@
protected void configure() {
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
bind(GlobalPluginConfigProvider.class).to(FileBasedGlobalPluginConfigProvider.class);
+ bind(AllProjectsConfigProvider.class).to(FileBasedAllProjectsConfigProvider.class);
bind(Path.class).annotatedWith(SitePath.class).toInstance(sitePath);
if (repoManager != null) {
diff --git a/java/com/google/gerrit/acceptance/SshSessionMina.java b/java/com/google/gerrit/acceptance/SshSessionMina.java
index 4d8691b..3b0ba3b 100644
--- a/java/com/google/gerrit/acceptance/SshSessionMina.java
+++ b/java/com/google/gerrit/acceptance/SshSessionMina.java
@@ -107,13 +107,11 @@
@Override
public int execAndReturnStatus(String command) throws Exception {
Process process = getMinaSession().exec(command, 0);
- InputStream in = process.getInputStream();
InputStream err = process.getErrorStream();
Scanner s = new Scanner(err, UTF_8.name()).useDelimiter("\\A");
error = s.hasNext() ? s.next() : null;
- s = new Scanner(in, UTF_8.name()).useDelimiter("\\A");
try {
return process.exitValue();
} catch (IllegalThreadStateException e) {
diff --git a/java/com/google/gerrit/acceptance/config/GlobalPluginConfig.java b/java/com/google/gerrit/acceptance/config/GlobalPluginConfig.java
index ae88e37..87063c9 100644
--- a/java/com/google/gerrit/acceptance/config/GlobalPluginConfig.java
+++ b/java/com/google/gerrit/acceptance/config/GlobalPluginConfig.java
@@ -28,12 +28,12 @@
/** Name of the plugin, corresponding to {@code $site/etc/@pluginName.config}. */
String pluginName();
- /** @see GerritConfig#name() */
+ /** See {@link GerritConfig#name()} */
String name();
- /** @see GerritConfig#value() */
+ /** See {@link GerritConfig#value()} */
String value() default "";
- /** @see GerritConfig#values() */
+ /** See {@link GerritConfig#values()} */
String[] values() default "";
}
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
index 3763f9a..c6457a4 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AccountsUpdate.ConfigureDeltaFromState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.notedb.Sequences;
import com.google.inject.Inject;
import java.io.IOException;
@@ -44,13 +45,18 @@
private final Accounts accounts;
private final AccountsUpdate accountsUpdate;
private final Sequences seq;
+ private final ExternalIdFactory externalIdFactory;
@Inject
public AccountOperationsImpl(
- Accounts accounts, @ServerInitiated AccountsUpdate accountsUpdate, Sequences seq) {
+ Accounts accounts,
+ @ServerInitiated AccountsUpdate accountsUpdate,
+ Sequences seq,
+ ExternalIdFactory externalIdFactory) {
this.accounts = accounts;
this.accountsUpdate = accountsUpdate;
this.seq = seq;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -72,7 +78,7 @@
return createdAccount.account().id();
}
- private static void initAccountDelta(
+ private void initAccountDelta(
AccountDelta.Builder builder, TestAccountCreation accountCreation, Account.Id accountId) {
accountCreation.fullname().ifPresent(builder::setFullName);
accountCreation.preferredEmail().ifPresent(e -> setPreferredEmail(builder, accountId, e));
@@ -84,19 +90,19 @@
.secondaryEmails()
.forEach(
secondaryEmail ->
- builder.addExternalId(ExternalId.createEmail(accountId, secondaryEmail)));
+ builder.addExternalId(externalIdFactory.createEmail(accountId, secondaryEmail)));
}
- private static void setPreferredEmail(
+ private void setPreferredEmail(
AccountDelta.Builder builder, Account.Id accountId, String preferredEmail) {
builder
.setPreferredEmail(preferredEmail)
- .addExternalId(ExternalId.createEmail(accountId, preferredEmail));
+ .addExternalId(externalIdFactory.createEmail(accountId, preferredEmail));
}
- private static void setUsername(
+ private void setUsername(
AccountDelta.Builder builder, Account.Id accountId, String username, String httpPassword) {
- builder.addExternalId(ExternalId.createUsername(username, accountId, httpPassword));
+ builder.addExternalId(externalIdFactory.createUsername(username, accountId, httpPassword));
}
private class PerAccountOperationsImpl implements PerAccountOperations {
@@ -202,14 +208,14 @@
.collect(toImmutableSet()));
builder.addExternalIds(
newSecondaryEmails.stream()
- .map(secondaryEmail -> ExternalId.createEmail(accountId, secondaryEmail))
+ .map(secondaryEmail -> externalIdFactory.createEmail(accountId, secondaryEmail))
.collect(toImmutableSet()));
if (accountUpdate.preferredEmail().isPresent()) {
builder.addExternalId(
- ExternalId.createEmail(accountId, accountUpdate.preferredEmail().get()));
+ externalIdFactory.createEmail(accountId, accountUpdate.preferredEmail().get()));
} else if (accountState.account().preferredEmail() != null) {
builder.addExternalId(
- ExternalId.createEmail(accountId, accountState.account().preferredEmail()));
+ externalIdFactory.createEmail(accountId, accountState.account().preferredEmail()));
}
}
diff --git a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperations.java b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperations.java
index 738be4d..2dd3f91 100644
--- a/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperations.java
+++ b/java/com/google/gerrit/acceptance/testsuite/project/ProjectOperations.java
@@ -81,11 +81,11 @@
*
* <p>Example:
*
- * <pre>
+ * <pre>{@code
* projectOperations.forInvalidation()
* .addProjectConfigUpdater(cfg -> cfg.setString("invalidSection", null, "foo", "bar"))
* .invalidate();
- * </pre>
+ * }</pre>
*
* <p><strong>Note:</strong> The invalidation will fail with an exception if the project to
* invalidate doesn't exist.
diff --git a/java/com/google/gerrit/auth/ldap/LdapRealm.java b/java/com/google/gerrit/auth/ldap/LdapRealm.java
index 9305914..9a9f309 100644
--- a/java/com/google/gerrit/auth/ldap/LdapRealm.java
+++ b/java/com/google/gerrit/auth/ldap/LdapRealm.java
@@ -32,6 +32,7 @@
import com.google.gerrit.server.account.EmailExpander;
import com.google.gerrit.server.account.GroupBackends;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.auth.AuthenticationUnavailableException;
import com.google.gerrit.server.auth.NoSuchUserException;
@@ -346,10 +347,12 @@
static class UserLoader extends CacheLoader<String, Optional<Account.Id>> {
private final ExternalIds externalIds;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- UserLoader(ExternalIds externalIds) {
+ UserLoader(ExternalIds externalIds, ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -358,7 +361,7 @@
TraceContext.newTimer(
"Loading account for username", Metadata.builder().username(username).build())) {
return externalIds
- .get(ExternalId.Key.create(SCHEME_GERRIT, username))
+ .get(externalIdKeyFactory.create(SCHEME_GERRIT, username))
.map(ExternalId::accountId);
}
}
diff --git a/java/com/google/gerrit/common/data/GitwebType.java b/java/com/google/gerrit/common/data/GitwebType.java
index 9cc408b..e69eacf 100644
--- a/java/com/google/gerrit/common/data/GitwebType.java
+++ b/java/com/google/gerrit/common/data/GitwebType.java
@@ -29,7 +29,7 @@
private char pathSeparator = '/';
private boolean urlEncode = true;
- /** @return name displayed in links. */
+ /** Returns name displayed in links. */
public String getLinkName() {
return name;
}
@@ -43,7 +43,7 @@
this.name = name;
}
- /** @return parameterized string for the branch URL. */
+ /** Returns parameterized string for the branch URL. */
public String getBranch() {
return branch;
}
@@ -57,7 +57,7 @@
branch = str;
}
- /** @return parameterized string for the tag URL. */
+ /** Returns parameterized string for the tag URL. */
public String getTag() {
return tag;
}
@@ -71,7 +71,7 @@
tag = str;
}
- /** @return parameterized string for the file URL. */
+ /** Returns parameterized string for the file URL. */
public String getFile() {
return file;
}
@@ -85,7 +85,7 @@
file = str;
}
- /** @return parameterized string for the file history URL. */
+ /** Returns parameterized string for the file history URL. */
public String getFileHistory() {
return fileHistory;
}
@@ -99,7 +99,7 @@
fileHistory = str;
}
- /** @return parameterized string for the project URL. */
+ /** Returns parameterized string for the project URL. */
public String getProject() {
return project;
}
@@ -113,7 +113,7 @@
project = str;
}
- /** @return parameterized string for the revision URL. */
+ /** Returns parameterized string for the revision URL. */
public String getRevision() {
return revision;
}
@@ -127,7 +127,7 @@
revision = str;
}
- /** @return parameterized string for the root tree URL. */
+ /** Returns parameterized string for the root tree URL. */
public String getRootTree() {
return rootTree;
}
@@ -141,7 +141,7 @@
rootTree = str;
}
- /** @return path separator used for branch and project names. */
+ /** Returns path separator used for branch and project names. */
public char getPathSeparator() {
return pathSeparator;
}
@@ -155,7 +155,7 @@
this.pathSeparator = separator;
}
- /** @return whether to URL encode path segments. */
+ /** Returns whether to URL encode path segments. */
public boolean getUrlEncode() {
return urlEncode;
}
diff --git a/java/com/google/gerrit/common/data/GlobalCapability.java b/java/com/google/gerrit/common/data/GlobalCapability.java
index 8bfd960..253266d 100644
--- a/java/com/google/gerrit/common/data/GlobalCapability.java
+++ b/java/com/google/gerrit/common/data/GlobalCapability.java
@@ -165,17 +165,17 @@
}
}
- /** @return all valid capability names. */
+ /** Returns all valid capability names. */
public static Collection<String> getAllNames() {
return Collections.unmodifiableList(NAMES_ALL);
}
- /** @return true if the name is recognized as a capability name. */
+ /** Returns true if the name is recognized as a capability name. */
public static boolean isGlobalCapability(String varName) {
return NAMES_LC.contains(varName.toLowerCase());
}
- /** @return true if the capability should have a range attached. */
+ /** Returns true if the capability should have a range attached. */
public static boolean hasRange(String varName) {
for (String n : RANGE_NAMES) {
if (n.equalsIgnoreCase(varName)) {
@@ -189,7 +189,7 @@
return Collections.unmodifiableList(Arrays.asList(RANGE_NAMES));
}
- /** @return the valid range for the capability if it has one, otherwise null. */
+ /** Returns the valid range for the capability if it has one, otherwise null. */
public static PermissionRange.WithDefaults getRange(String varName) {
if (QUERY_LIMIT.equalsIgnoreCase(varName)) {
return new PermissionRange.WithDefaults(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticVersion.java b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
index c6400df..b5bf44b 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticVersion.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticVersion.java
@@ -45,7 +45,6 @@
*
* @param version for which to return an ElasticVersion
* @return the corresponding ElasticVersion if supported
- * @throws UnsupportedVersion
*/
public static ElasticVersion forVersion(String version) {
for (ElasticVersion value : ElasticVersion.values()) {
diff --git a/java/com/google/gerrit/entities/AccessSection.java b/java/com/google/gerrit/entities/AccessSection.java
index d97bca8..69a234a 100644
--- a/java/com/google/gerrit/entities/AccessSection.java
+++ b/java/com/google/gerrit/entities/AccessSection.java
@@ -52,7 +52,7 @@
return new AutoValue_AccessSection.Builder().setName(name).setPermissions(ImmutableList.of());
}
- /** @return true if the name is likely to be a valid reference section name. */
+ /** Returns true if the name is likely to be a valid reference section name. */
public static boolean isValidRefSectionName(String name) {
return name.startsWith("refs/") || name.startsWith("^refs/");
}
diff --git a/java/com/google/gerrit/entities/AccountGroup.java b/java/com/google/gerrit/entities/AccountGroup.java
index 0b2a346..001a544 100644
--- a/java/com/google/gerrit/entities/AccountGroup.java
+++ b/java/com/google/gerrit/entities/AccountGroup.java
@@ -54,7 +54,7 @@
return uuid();
}
- /** @return true if the UUID is for a group managed within Gerrit. */
+ /** Returns true if the UUID is for a group managed within Gerrit. */
public boolean isInternalGroup() {
return get().matches("^[0-9a-f]{40}$");
}
diff --git a/java/com/google/gerrit/entities/Address.java b/java/com/google/gerrit/entities/Address.java
index 2324330..5d63476 100644
--- a/java/com/google/gerrit/entities/Address.java
+++ b/java/com/google/gerrit/entities/Address.java
@@ -15,6 +15,7 @@
package com.google.gerrit.entities;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.gerrit.common.Nullable;
/** Represents an address (name + email) in an email message. */
@@ -66,8 +67,9 @@
public abstract String email();
+ @Memoized
@Override
- public final int hashCode() {
+ public int hashCode() {
return email().hashCode();
}
diff --git a/java/com/google/gerrit/entities/GroupDescription.java b/java/com/google/gerrit/entities/GroupDescription.java
index e950257..7054bed 100644
--- a/java/com/google/gerrit/entities/GroupDescription.java
+++ b/java/com/google/gerrit/entities/GroupDescription.java
@@ -22,22 +22,22 @@
public class GroupDescription {
/** The Basic information required to be exposed by any Group. */
public interface Basic {
- /** @return the non-null UUID of the group. */
+ /** Returns the non-null UUID of the group. */
AccountGroup.UUID getGroupUUID();
- /** @return the non-null name of the group. */
+ /** Returns the non-null name of the group. */
String getName();
/**
- * @return optional email address to send to the group's members. If provided, Gerrit will use
- * this email address to send change notifications to the group.
+ * Returns optional email address to send to the group's members. If provided, Gerrit will use
+ * this email address to send change notifications to the group.
*/
@Nullable
String getEmailAddress();
/**
- * @return optional URL to information about the group. Typically a URL to a web page that
- * permits users to apply to join the group, or manage their membership.
+ * Returns optional URL to information about the group. Typically a URL to a web page that
+ * permits users to apply to join the group, or manage their membership.
*/
@Nullable
String getUrl();
diff --git a/java/com/google/gerrit/entities/GroupReference.java b/java/com/google/gerrit/entities/GroupReference.java
index 208ba0f..125153e 100644
--- a/java/com/google/gerrit/entities/GroupReference.java
+++ b/java/com/google/gerrit/entities/GroupReference.java
@@ -17,6 +17,7 @@
import static java.util.Objects.requireNonNull;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.gerrit.common.Nullable;
/** Describes a group within a projects {@link AccessSection}s. */
@@ -78,8 +79,9 @@
return "?";
}
+ @Memoized
@Override
- public final int hashCode() {
+ public int hashCode() {
return uuid(this).hashCode();
}
diff --git a/java/com/google/gerrit/entities/ImmutableConfig.java b/java/com/google/gerrit/entities/ImmutableConfig.java
index a5efc14..83a44d1 100644
--- a/java/com/google/gerrit/entities/ImmutableConfig.java
+++ b/java/com/google/gerrit/entities/ImmutableConfig.java
@@ -51,27 +51,27 @@
return cfg;
}
- /** @see Config#getSections() */
+ /** See {@link Config#getSections()} */
public Set<String> getSections() {
return cfg.getSections();
}
- /** @see Config#getNames(String) */
+ /** See {@link Config#getNames(String)} */
public Set<String> getNames(String section) {
return cfg.getNames(section);
}
- /** @see Config#getNames(String, String) */
+ /** See {@link Config#getNames(String, String)} */
public Set<String> getNames(String section, String subsection) {
return cfg.getNames(section, subsection);
}
- /** @see Config#getStringList(String, String, String) */
+ /** See {@link Config#getStringList(String, String, String)} */
public String[] getStringList(String section, String subsection, String name) {
return cfg.getStringList(section, subsection, name);
}
- /** @see Config#getSubsections(String) */
+ /** See {@link Config#getSubsections(String)} */
public Set<String> getSubsections(String section) {
return cfg.getSubsections(section);
}
diff --git a/java/com/google/gerrit/entities/NotifyConfig.java b/java/com/google/gerrit/entities/NotifyConfig.java
index 17da81f..5c0a3db 100644
--- a/java/com/google/gerrit/entities/NotifyConfig.java
+++ b/java/com/google/gerrit/entities/NotifyConfig.java
@@ -15,6 +15,7 @@
package com.google.gerrit.entities;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.common.Nullable;
@@ -106,8 +107,9 @@
return getName().compareTo(o.getName());
}
+ @Memoized
@Override
- public final int hashCode() {
+ public int hashCode() {
return getName().hashCode();
}
diff --git a/java/com/google/gerrit/entities/Patch.java b/java/com/google/gerrit/entities/Patch.java
index 856765b..2d28046 100644
--- a/java/com/google/gerrit/entities/Patch.java
+++ b/java/com/google/gerrit/entities/Patch.java
@@ -78,25 +78,27 @@
public abstract String fileName();
}
- /** Type of modification made to the file path. */
+ /**
+ * Type of modification made to the file path. Ordering of values matters (used by diff cache).
+ */
public enum ChangeType implements CodedEnum {
/** Path is being created/introduced by this patch. */
ADDED('A'),
- /** Path already exists, and has updated content. */
- MODIFIED('M'),
-
- /** Path existed, but is being removed by this patch. */
- DELETED('D'),
-
/** Path existed at the source but was moved. */
RENAMED('R'),
+ /** Path already exists, and has updated content. */
+ MODIFIED('M'),
+
/** Path was copied from the source. */
COPIED('C'),
/** Sufficient amount of content changed to claim the file was rewritten. */
- REWRITE('W');
+ REWRITE('W'),
+
+ /** Path existed, but is being removed by this patch. */
+ DELETED('D');
private final char code;
diff --git a/java/com/google/gerrit/entities/PatchSetApproval.java b/java/com/google/gerrit/entities/PatchSetApproval.java
index a4bb251..f853f77 100644
--- a/java/com/google/gerrit/entities/PatchSetApproval.java
+++ b/java/com/google/gerrit/entities/PatchSetApproval.java
@@ -41,7 +41,7 @@
}
public static Builder builder() {
- return new AutoValue_PatchSetApproval.Builder().postSubmit(false);
+ return new AutoValue_PatchSetApproval.Builder().postSubmit(false).copied(false);
}
@AutoValue.Builder
@@ -72,6 +72,8 @@
public abstract Builder postSubmit(boolean isPostSubmit);
+ public abstract Builder copied(boolean isCopied);
+
abstract PatchSetApproval autoBuild();
public PatchSetApproval build() {
@@ -111,10 +113,12 @@
public abstract boolean postSubmit();
+ public abstract boolean copied();
+
public abstract Builder toBuilder();
public PatchSetApproval copyWithPatchSet(PatchSet.Id psId) {
- return toBuilder().key(key(psId, key().accountId(), key().labelId())).build();
+ return toBuilder().key(key(psId, key().accountId(), key().labelId())).copied(true).build();
}
public PatchSet.Id patchSetId() {
diff --git a/java/com/google/gerrit/entities/Permission.java b/java/com/google/gerrit/entities/Permission.java
index 322c79e..95164bd 100644
--- a/java/com/google/gerrit/entities/Permission.java
+++ b/java/com/google/gerrit/entities/Permission.java
@@ -95,7 +95,7 @@
LABEL_AS_INDEX = NAMES_LC.indexOf(Permission.LABEL_AS.toLowerCase());
}
- /** @return true if the name is recognized as a permission name. */
+ /** Returns true if the name is recognized as a permission name. */
public static boolean isPermission(String varName) {
return isLabel(varName) || isLabelAs(varName) || NAMES_LC.contains(varName.toLowerCase());
}
@@ -104,22 +104,22 @@
return isLabel(varName) || isLabelAs(varName);
}
- /** @return true if the permission name is actually for a review label. */
+ /** Returns true if the permission name is actually for a review label. */
public static boolean isLabel(String varName) {
return varName.startsWith(LABEL) && LABEL.length() < varName.length();
}
- /** @return true if the permission is for impersonated review labels. */
+ /** Returns true if the permission is for impersonated review labels. */
public static boolean isLabelAs(String var) {
return var.startsWith(LABEL_AS) && LABEL_AS.length() < var.length();
}
- /** @return permission name for the given review label. */
+ /** Returns permission name for the given review label. */
public static String forLabel(String labelName) {
return LABEL + labelName;
}
- /** @return permission name to apply a label for another user. */
+ /** Returns permission name to apply a label for another user. */
public static String forLabelAs(String labelName) {
return LABEL_AS + labelName;
}
diff --git a/java/com/google/gerrit/entities/PermissionRange.java b/java/com/google/gerrit/entities/PermissionRange.java
index fa9f4c2..d283069 100644
--- a/java/com/google/gerrit/entities/PermissionRange.java
+++ b/java/com/google/gerrit/entities/PermissionRange.java
@@ -46,7 +46,7 @@
defaultMax = max;
}
- /** @return all values between {@link #getMin()} and {@link #getMax()} */
+ /** Returns all values between {@link #getMin()} and {@link #getMax()} */
public List<Integer> getValuesAsList() {
ArrayList<Integer> r = new ArrayList<>(getRangeSize());
for (int i = min; i <= max; i++) {
@@ -55,7 +55,7 @@
return r;
}
- /** @return number of values between {@link #getMin()} and {@link #getMax()} */
+ /** Returns number of values between {@link #getMin()} and {@link #getMax()} */
public int getRangeSize() {
return max - min;
}
diff --git a/java/com/google/gerrit/entities/SubmitRecord.java b/java/com/google/gerrit/entities/SubmitRecord.java
index 860997f..95ad9f8 100644
--- a/java/com/google/gerrit/entities/SubmitRecord.java
+++ b/java/com/google/gerrit/entities/SubmitRecord.java
@@ -68,6 +68,8 @@
}
}
+ // Name of the rule that created this submit record, formatted as '$pluginName~$ruleName'
+ public String ruleName;
public Status status;
public List<Label> labels;
public List<LegacySubmitRequirement> requirements;
@@ -158,6 +160,7 @@
*/
public SubmitRecord deepCopy() {
SubmitRecord copy = new SubmitRecord();
+ copy.ruleName = ruleName;
copy.status = status;
copy.errorMessage = errorMessage;
if (labels != null) {
diff --git a/java/com/google/gerrit/entities/SubmitRequirementResult.java b/java/com/google/gerrit/entities/SubmitRequirementResult.java
index e1d5f39..4f2f2f6 100644
--- a/java/com/google/gerrit/entities/SubmitRequirementResult.java
+++ b/java/com/google/gerrit/entities/SubmitRequirementResult.java
@@ -41,6 +41,12 @@
/** SHA-1 of the patchset commit ID for which the submit requirement was evaluated. */
public abstract ObjectId patchSetCommitId();
+ /**
+ * Whether this result was created from a legacy {@link SubmitRecord}, or by evaluating a {@link
+ * SubmitRequirement}.
+ */
+ public abstract boolean legacy();
+
@Memoized
public Status status() {
if (assertError(submittabilityExpressionResult())
@@ -109,6 +115,8 @@
public abstract Builder patchSetCommitId(ObjectId value);
+ public abstract Builder legacy(boolean value);
+
public abstract SubmitRequirementResult build();
}
diff --git a/java/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverter.java b/java/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverter.java
index 78a35ff..9e77025 100644
--- a/java/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverter.java
+++ b/java/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverter.java
@@ -39,7 +39,8 @@
.setKey(patchSetApprovalKeyProtoConverter.toProto(patchSetApproval.key()))
.setValue(patchSetApproval.value())
.setGranted(patchSetApproval.granted().getTime())
- .setPostSubmit(patchSetApproval.postSubmit());
+ .setPostSubmit(patchSetApproval.postSubmit())
+ .setCopied(patchSetApproval.copied());
patchSetApproval.tag().ifPresent(builder::setTag);
Account.Id realAccountId = patchSetApproval.realAccountId();
@@ -61,7 +62,8 @@
.key(patchSetApprovalKeyProtoConverter.fromProto(proto.getKey()))
.value(proto.getValue())
.granted(new Timestamp(proto.getGranted()))
- .postSubmit(proto.getPostSubmit());
+ .postSubmit(proto.getPostSubmit())
+ .copied(proto.getCopied());
if (proto.hasTag()) {
builder.tag(proto.getTag());
}
diff --git a/java/com/google/gerrit/extensions/BUILD b/java/com/google/gerrit/extensions/BUILD
index 21949f7..f36018b 100644
--- a/java/com/google/gerrit/extensions/BUILD
+++ b/java/com/google/gerrit/extensions/BUILD
@@ -34,6 +34,7 @@
"//java/com/google/gerrit/common:annotations",
"//lib:guava",
"//lib/auto:auto-value-annotations",
+ "//lib/errorprone:annotations",
"//lib/guice",
"//lib/guice:guice-assistedinject",
],
diff --git a/java/com/google/gerrit/extensions/api/accounts/AccountApi.java b/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
index 6df9889..9c9c282 100644
--- a/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
+++ b/java/com/google/gerrit/extensions/api/accounts/AccountApi.java
@@ -14,7 +14,6 @@
package com.google.gerrit.extensions.api.accounts;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
@@ -23,7 +22,6 @@
import com.google.gerrit.extensions.common.AccountExternalIdInfo;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.AgreementInfo;
-import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.EmailInfo;
import com.google.gerrit.extensions.common.GpgKeyInfo;
import com.google.gerrit.extensions.common.GroupInfo;
@@ -32,7 +30,6 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import java.util.List;
import java.util.Map;
-import java.util.SortedSet;
public interface AccountApi {
AccountInfo get() throws RestApiException;
@@ -67,12 +64,6 @@
void unstarChange(String changeId) throws RestApiException;
- void setStars(String changeId, StarsInput input) throws RestApiException;
-
- SortedSet<String> getStars(String changeId) throws RestApiException;
-
- List<ChangeInfo> getStarredChanges() throws RestApiException;
-
List<GroupInfo> getGroups() throws RestApiException;
List<EmailInfo> getEmails() throws RestApiException;
@@ -221,21 +212,6 @@
}
@Override
- public void setStars(String changeId, StarsInput input) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
- public SortedSet<String> getStars(String changeId) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
- public List<ChangeInfo> getStarredChanges() throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public List<GroupInfo> getGroups() throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/api/accounts/Accounts.java b/java/com/google/gerrit/extensions/api/accounts/Accounts.java
index 15fca9a..285b385 100644
--- a/java/com/google/gerrit/extensions/api/accounts/Accounts.java
+++ b/java/com/google/gerrit/extensions/api/accounts/Accounts.java
@@ -38,7 +38,11 @@
*/
AccountApi id(String id) throws RestApiException;
- /** @see #id(String) */
+ /**
+ * Look up an account by ID. #id(String)
+ *
+ * <p>See #id(String)
+ */
AccountApi id(int id) throws RestApiException;
/**
diff --git a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
index 04f5bd2..690ba4e 100644
--- a/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/ChangeApi.java
@@ -140,14 +140,6 @@
boolean ignored() throws RestApiException;
/**
- * Mark this change as reviewed/unreviewed.
- *
- * @param reviewed flag to decide if this change should be marked as reviewed ({@code true}) or
- * unreviewed ({@code false})
- */
- void markAsReviewed(boolean reviewed) throws RestApiException;
-
- /**
* Create a new change that reverts this change.
*
* @see Changes#id(int)
@@ -332,7 +324,6 @@
* Get hashtags on a change.
*
* @return hashtags
- * @throws RestApiException
*/
Set<String> getHashtags() throws RestApiException;
@@ -367,7 +358,6 @@
*
* @return comments in a map keyed by path; comments have the {@code revision} field set to
* indicate their patch set.
- * @throws RestApiException
* @deprecated Callers should use {@link #commentsRequest()} instead
*/
@Deprecated
@@ -380,7 +370,6 @@
*
* @return comments as a list; comments have the {@code revision} field set to indicate their
* patch set.
- * @throws RestApiException
* @deprecated Callers should use {@link #commentsRequest()} instead
*/
@Deprecated
@@ -401,7 +390,6 @@
*
* @return robot comments in a map keyed by path; robot comments have the {@code revision} field
* set to indicate their patch set.
- * @throws RestApiException
*/
Map<String, List<RobotCommentInfo>> robotComments() throws RestApiException;
@@ -410,7 +398,6 @@
*
* @return drafts in a map keyed by path; comments have the {@code revision} field set to indicate
* their patch set.
- * @throws RestApiException
*/
default Map<String, List<CommentInfo>> drafts() throws RestApiException {
return draftsRequest().get();
@@ -421,7 +408,6 @@
*
* @return drafts as a list; comments have the {@code revision} field set to indicate their patch
* set.
- * @throws RestApiException
*/
default List<CommentInfo> draftsAsList() throws RestApiException {
return draftsRequest().getAsList();
@@ -451,7 +437,6 @@
* Get all messages of a change with detailed account info.
*
* @return a list of messages sorted by their creation time.
- * @throws RestApiException
*/
List<ChangeMessageInfo> messages() throws RestApiException;
@@ -474,7 +459,6 @@
*
* @return comments in a map keyed by path; comments have the {@code revision} field set to
* indicate their patch set.
- * @throws RestApiException
*/
public abstract Map<String, List<CommentInfo>> get() throws RestApiException;
@@ -814,11 +798,6 @@
}
@Override
- public void markAsReviewed(boolean reviewed) throws RestApiException {
- throw new NotImplementedException();
- }
-
- @Override
public PureRevertInfo pureRevert() throws RestApiException {
throw new NotImplementedException();
}
diff --git a/java/com/google/gerrit/extensions/api/changes/FileApi.java b/java/com/google/gerrit/extensions/api/changes/FileApi.java
index 26f9452..e20ac56 100644
--- a/java/com/google/gerrit/extensions/api/changes/FileApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/FileApi.java
@@ -29,10 +29,18 @@
/** Diff against the revision's parent version of the file. */
DiffInfo diff() throws RestApiException;
- /** @param base revision id of the revision to be used as the diff base */
+ /**
+ * Diff against the specified base
+ *
+ * @param base revision id of the revision to be used as the diff base
+ */
DiffInfo diff(String base) throws RestApiException;
- /** @param parent 1-based parent number to diff against */
+ /**
+ * Diff against the specified parent
+ *
+ * @param parent 1-based parent number to diff against
+ */
DiffInfo diff(int parent) throws RestApiException;
/**
diff --git a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 229b9d4..1307516 100644
--- a/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -160,7 +160,6 @@
*
* @param format the format of the archive
* @return the archive as {@link BinaryResult}
- * @throws RestApiException
*/
BinaryResult getArchive(ArchiveFormat format) throws RestApiException;
diff --git a/java/com/google/gerrit/extensions/api/changes/StarsInput.java b/java/com/google/gerrit/extensions/api/changes/StarsInput.java
deleted file mode 100644
index 1207d27..0000000
--- a/java/com/google/gerrit/extensions/api/changes/StarsInput.java
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (C) 2016 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.extensions.api.changes;
-
-import java.util.Set;
-
-public class StarsInput {
- public Set<String> add;
- public Set<String> remove;
-
- public StarsInput() {}
-
- public StarsInput(Set<String> add) {
- this.add = add;
- }
-
- public StarsInput(Set<String> add, Set<String> remove) {
- this.add = add;
- this.remove = remove;
- }
-}
diff --git a/java/com/google/gerrit/extensions/api/config/Config.java b/java/com/google/gerrit/extensions/api/config/Config.java
index eb7288d..041e1dd 100644
--- a/java/com/google/gerrit/extensions/api/config/Config.java
+++ b/java/com/google/gerrit/extensions/api/config/Config.java
@@ -17,7 +17,7 @@
import com.google.gerrit.extensions.restapi.NotImplementedException;
public interface Config {
- /** @return An API for getting server related configurations. */
+ /** Returns an API for getting server related configurations. */
Server server();
/**
diff --git a/java/com/google/gerrit/extensions/api/config/ConsistencyCheckInfo.java b/java/com/google/gerrit/extensions/api/config/ConsistencyCheckInfo.java
index e582f1b..9fb57ad 100644
--- a/java/com/google/gerrit/extensions/api/config/ConsistencyCheckInfo.java
+++ b/java/com/google/gerrit/extensions/api/config/ConsistencyCheckInfo.java
@@ -14,6 +14,7 @@
package com.google.gerrit.extensions.api.config;
+import com.google.errorprone.annotations.FormatMethod;
import java.util.List;
import java.util.Objects;
@@ -80,10 +81,12 @@
return status.name() + ": " + message;
}
+ @FormatMethod
public static ConsistencyProblemInfo warning(String fmt, Object... args) {
return new ConsistencyProblemInfo(Status.WARNING, String.format(fmt, args));
}
+ @FormatMethod
public static ConsistencyProblemInfo error(String fmt, Object... args) {
return new ConsistencyProblemInfo(Status.ERROR, String.format(fmt, args));
}
diff --git a/java/com/google/gerrit/extensions/api/config/Server.java b/java/com/google/gerrit/extensions/api/config/Server.java
index 70d1bff..8b69ded 100644
--- a/java/com/google/gerrit/extensions/api/config/Server.java
+++ b/java/com/google/gerrit/extensions/api/config/Server.java
@@ -24,7 +24,7 @@
import java.util.List;
public interface Server {
- /** @return Version of server. */
+ /** Returns version of server. */
String getVersion() throws RestApiException;
ServerInfo getInfo() throws RestApiException;
diff --git a/java/com/google/gerrit/extensions/api/groups/GroupApi.java b/java/com/google/gerrit/extensions/api/groups/GroupApi.java
index 067f120..e1b3a9f 100644
--- a/java/com/google/gerrit/extensions/api/groups/GroupApi.java
+++ b/java/com/google/gerrit/extensions/api/groups/GroupApi.java
@@ -24,53 +24,49 @@
import java.util.List;
public interface GroupApi {
- /** @return group info with no {@code ListGroupsOption}s set. */
+ /** Returns group info with no {@code ListGroupsOption}s set. */
GroupInfo get() throws RestApiException;
- /** @return group info with all {@code ListGroupsOption}s set. */
+ /** Returns group info with all {@code ListGroupsOption}s set. */
GroupInfo detail() throws RestApiException;
- /** @return group name. */
+ /** Returns group name. */
String name() throws RestApiException;
/**
* Set group name.
*
* @param name new name.
- * @throws RestApiException
*/
void name(String name) throws RestApiException;
- /** @return owning group info. */
+ /** Returns owning group info. */
GroupInfo owner() throws RestApiException;
/**
* Set group owner.
*
* @param owner identifier of new group owner.
- * @throws RestApiException
*/
void owner(String owner) throws RestApiException;
- /** @return group description. */
+ /** Returns group description. */
String description() throws RestApiException;
/**
* Set group decsription.
*
* @param description new description.
- * @throws RestApiException
*/
void description(String description) throws RestApiException;
- /** @return group options. */
+ /** Returns group options. */
GroupOptionsInfo options() throws RestApiException;
/**
* Set group options.
*
* @param options new options.
- * @throws RestApiException
*/
void options(GroupOptionsInfo options) throws RestApiException;
@@ -78,7 +74,6 @@
* List group members, non-recursively.
*
* @return group members.
- * @throws RestApiException
*/
List<AccountInfo> members() throws RestApiException;
@@ -87,7 +82,6 @@
*
* @param recursive whether to recursively included groups.
* @return group members.
- * @throws RestApiException
*/
List<AccountInfo> members(boolean recursive) throws RestApiException;
@@ -96,7 +90,6 @@
*
* @param members list of member identifiers, in any format accepted by {@link
* com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
- * @throws RestApiException
*/
void addMembers(List<String> members) throws RestApiException;
@@ -105,7 +98,6 @@
*
* @param members list of member identifiers, in any format accepted by {@link
* com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
- * @throws RestApiException
*/
default void addMembers(String... members) throws RestApiException {
addMembers(Arrays.asList(members));
@@ -116,7 +108,6 @@
*
* @param members list of member identifiers, in any format accepted by {@link
* com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
- * @throws RestApiException
*/
void removeMembers(List<String> members) throws RestApiException;
@@ -125,7 +116,6 @@
*
* @param members list of member identifiers, in any format accepted by {@link
* com.google.gerrit.extensions.api.accounts.Accounts#id(String)}
- * @throws RestApiException
*/
default void removeMembers(String... members) throws RestApiException {
removeMembers(Arrays.asList(members));
@@ -135,7 +125,6 @@
* Lists the subgroups of this group.
*
* @return the found subgroups
- * @throws RestApiException
*/
List<GroupInfo> includedGroups() throws RestApiException;
@@ -143,7 +132,6 @@
* Adds subgroups to this group.
*
* @param groups list of group identifiers, in any format accepted by {@link Groups#id(String)}
- * @throws RestApiException
*/
void addGroups(List<String> groups) throws RestApiException;
@@ -151,7 +139,6 @@
* Adds subgroups to this group.
*
* @param groups list of group identifiers, in any format accepted by {@link Groups#id(String)}
- * @throws RestApiException
*/
default void addGroups(String... groups) throws RestApiException {
addGroups(Arrays.asList(groups));
@@ -161,7 +148,6 @@
* Removes subgroups from this group.
*
* @param groups list of group identifiers, in any format accepted by {@link Groups#id(String)}
- * @throws RestApiException
*/
void removeGroups(List<String> groups) throws RestApiException;
@@ -169,7 +155,6 @@
* Removes subgroups from this group.
*
* @param groups list of group identifiers, in any format accepted by {@link Groups#id(String)}
- * @throws RestApiException
*/
default void removeGroups(String... groups) throws RestApiException {
removeGroups(Arrays.asList(groups));
@@ -179,7 +164,6 @@
* Returns the audit log of the group.
*
* @return list of audit events of the group.
- * @throws RestApiException
*/
List<? extends GroupAuditEventInfo> auditLog() throws RestApiException;
@@ -187,8 +171,6 @@
* Reindexes the group.
*
* <p>Only supported for internal groups.
- *
- * @throws RestApiException
*/
void index() throws RestApiException;
diff --git a/java/com/google/gerrit/extensions/api/groups/Groups.java b/java/com/google/gerrit/extensions/api/groups/Groups.java
index 81b5f47..1a46930 100644
--- a/java/com/google/gerrit/extensions/api/groups/Groups.java
+++ b/java/com/google/gerrit/extensions/api/groups/Groups.java
@@ -47,7 +47,7 @@
/** Create a new group. */
GroupApi create(GroupInput input) throws RestApiException;
- /** @return new request for listing groups. */
+ /** Returns new request for listing groups. */
ListRequest list();
/**
diff --git a/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java b/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java
index 417f55a..c3d760b 100644
--- a/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java
+++ b/java/com/google/gerrit/extensions/auth/oauth/OAuthServiceProvider.java
@@ -40,9 +40,7 @@
* After establishing of secure communication channel, this method supossed to access the
* protected resoure and retrieve the username.
*
- * @param token
* @return OAuth user information
- * @throws IOException
*/
OAuthUserInfo getUserInfo(OAuthToken token) throws IOException;
diff --git a/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java b/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
index 21b319e..b26f435 100644
--- a/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
+++ b/java/com/google/gerrit/extensions/client/GeneralPreferencesInfo.java
@@ -148,6 +148,7 @@
public DefaultBase defaultBaseForMerges;
public Boolean publishCommentsOnPush;
public Boolean disableKeyboardShortcuts;
+ public Boolean disableTokenHighlighting;
public Boolean workInProgressByDefault;
public List<MenuItem> my;
public List<String> changeTable;
@@ -207,6 +208,7 @@
p.defaultBaseForMerges = DefaultBase.FIRST_PARENT;
p.publishCommentsOnPush = false;
p.disableKeyboardShortcuts = false;
+ p.disableTokenHighlighting = false;
p.workInProgressByDefault = false;
return p;
}
diff --git a/java/com/google/gerrit/extensions/common/AccountInfo.java b/java/com/google/gerrit/extensions/common/AccountInfo.java
index 60ba18d..4701e86 100644
--- a/java/com/google/gerrit/extensions/common/AccountInfo.java
+++ b/java/com/google/gerrit/extensions/common/AccountInfo.java
@@ -27,10 +27,13 @@
* are defined in {@link AccountDetailInfo}.
*/
public class AccountInfo {
- /** Tags are additional properties of an account. */
- public enum Tag {
+ /**
+ * Tags are additional properties of an account. These are just tags known to Gerrit core. Plugins
+ * may define their own.
+ */
+ public static final class Tags {
/** Tag indicating that this account is a service user. */
- SERVICE_USER
+ public static final String SERVICE_USER = "SERVICE_USER";
}
/** The numeric ID of the account. */
@@ -74,7 +77,7 @@
public Boolean inactive;
/** Tags, such as whether this account is a service user. */
- public List<Tag> tags;
+ public List<String> tags;
public AccountInfo(Integer id) {
this._accountId = id;
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfo.java b/java/com/google/gerrit/extensions/common/ChangeInfo.java
index 6afe8ac..2bb3dd7 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -112,6 +112,7 @@
public List<PluginDefinedInfo> plugins;
public Collection<TrackingIdInfo> trackingIds;
public Collection<LegacySubmitRequirementInfo> requirements;
+ public Collection<SubmitRecordInfo> submitRecords;
public Collection<SubmitRequirementResultInfo> submitRequirements;
public ChangeInfo() {}
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfoDiffer.java b/java/com/google/gerrit/extensions/common/ChangeInfoDiffer.java
index 0447e80..ad112d3 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfoDiffer.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfoDiffer.java
@@ -63,9 +63,12 @@
*/
public static ChangeInfoDifference getDifference(
ChangeInfo oldChangeInfo, ChangeInfo newChangeInfo) {
- return ChangeInfoDifference.create(
- /* added= */ getAdded(oldChangeInfo, newChangeInfo),
- /* removed= */ getAdded(newChangeInfo, oldChangeInfo));
+ return ChangeInfoDifference.builder()
+ .setOldChangeInfo(oldChangeInfo)
+ .setNewChangeInfo(newChangeInfo)
+ .setAdded(getAdded(oldChangeInfo, newChangeInfo))
+ .setRemoved(getAdded(newChangeInfo, oldChangeInfo))
+ .build();
}
@SuppressWarnings("unchecked") // reflection is used to construct instances of T
@@ -143,7 +146,7 @@
}
}
- /** @return {@code null} if nothing has been added to {@code oldCollection} */
+ /** Returns {@code null} if nothing has been added to {@code oldCollection} */
private static ImmutableList<?> getAddedForCollection(
Collection<?> oldCollection, Collection<?> newCollection) {
ImmutableList<?> notInOldCollection = getAdditions(oldCollection, newCollection);
@@ -165,7 +168,7 @@
return duplicatesMap.values().stream().flatMap(Collection::stream).collect(toImmutableList());
}
- /** @return {@code null} if nothing has been added to {@code oldMap} */
+ /** Returns {@code null} if nothing has been added to {@code oldMap} */
private static ImmutableMap<Object, Object> getAddedForMap(Map<?, ?> oldMap, Map<?, ?> newMap) {
ImmutableMap.Builder<Object, Object> additionsBuilder = ImmutableMap.builder();
for (Map.Entry<?, ?> entry : newMap.entrySet()) {
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfoDifference.java b/java/com/google/gerrit/extensions/common/ChangeInfoDifference.java
index 269c673..997c3ee 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfoDifference.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfoDifference.java
@@ -20,11 +20,29 @@
@AutoValue
public abstract class ChangeInfoDifference {
+ public abstract ChangeInfo oldChangeInfo();
+
+ public abstract ChangeInfo newChangeInfo();
+
public abstract ChangeInfo added();
public abstract ChangeInfo removed();
- public static ChangeInfoDifference create(ChangeInfo added, ChangeInfo removed) {
- return new AutoValue_ChangeInfoDifference(added, removed);
+ public static Builder builder() {
+ return new AutoValue_ChangeInfoDifference.Builder();
+ }
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public abstract Builder setOldChangeInfo(ChangeInfo oldChangeInfo);
+
+ public abstract Builder setNewChangeInfo(ChangeInfo newChangeInfo);
+
+ public abstract Builder setAdded(ChangeInfo added);
+
+ public abstract Builder setRemoved(ChangeInfo removed);
+
+ public abstract ChangeInfoDifference build();
}
}
diff --git a/java/com/google/gerrit/extensions/common/SubmitRecordInfo.java b/java/com/google/gerrit/extensions/common/SubmitRecordInfo.java
new file mode 100644
index 0000000..09c9841
--- /dev/null
+++ b/java/com/google/gerrit/extensions/common/SubmitRecordInfo.java
@@ -0,0 +1,48 @@
+// 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.extensions.common;
+
+import java.util.List;
+
+/** API response containing a {@link com.google.gerrit.entities.SubmitRecord} entity. */
+public class SubmitRecordInfo {
+ public enum Status {
+ OK,
+ NOT_READY,
+ CLOSED,
+ FORCED,
+ RULE_ERROR
+ }
+
+ public static class Label {
+ public enum Status {
+ OK,
+ REJECT,
+ NEED,
+ MAY,
+ IMPOSSIBLE
+ }
+
+ public String label;
+ public Status status;
+ public AccountInfo appliedBy;
+ }
+
+ public String ruleName;
+ public Status status;
+ public List<Label> labels;
+ public List<LegacySubmitRequirementInfo> requirements;
+ public String errorMessage;
+}
diff --git a/java/com/google/gerrit/extensions/common/SubmitRequirementResultInfo.java b/java/com/google/gerrit/extensions/common/SubmitRequirementResultInfo.java
index 685e81a..d17da0a 100644
--- a/java/com/google/gerrit/extensions/common/SubmitRequirementResultInfo.java
+++ b/java/com/google/gerrit/extensions/common/SubmitRequirementResultInfo.java
@@ -47,6 +47,9 @@
/** Overall result (status) of evaluating this submit requirement. */
public Status status;
+ /** Whether this result was created from a legacy submit record. */
+ public boolean isLegacy;
+
/** Result of evaluating the applicability expression. */
public SubmitRequirementExpressionInfo applicabilityExpressionResult;
diff --git a/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java b/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
index deb03b0..2af9a767 100644
--- a/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
+++ b/java/com/google/gerrit/extensions/common/TestSubmitRuleInfo.java
@@ -19,7 +19,7 @@
import java.util.Objects;
public class TestSubmitRuleInfo {
- /** @see com.google.gerrit.entities.SubmitRecord.Status */
+ /** See {@link com.google.gerrit.entities.SubmitRecord.Status} */
public String status;
public String errorMessage;
diff --git a/java/com/google/gerrit/extensions/conditions/BooleanCondition.java b/java/com/google/gerrit/extensions/conditions/BooleanCondition.java
index 162dd99..9c354fb 100644
--- a/java/com/google/gerrit/extensions/conditions/BooleanCondition.java
+++ b/java/com/google/gerrit/extensions/conditions/BooleanCondition.java
@@ -48,7 +48,7 @@
BooleanCondition() {}
- /** @return evaluate the condition and return its value. */
+ /** Evaluates the condition and return its value. */
public abstract boolean value();
/**
@@ -63,7 +63,9 @@
* Reduce evaluation tree by cutting off branches that evaluate trivially and replacing them with
* a leave note corresponding to the value the branch evaluated to.
*
- * <p><code>
+ * <p>
+ *
+ * <pre>{@code
* Example 1 (T=True, F=False, C=non-trivial check):
* OR
* / \ => T
@@ -76,7 +78,7 @@
* AND
* / \ => F
* T F
- * </code>
+ * }</pre>
*
* <p>There is no guarantee that the resulting tree is minimal. The only guarantee made is that
* branches that evaluate trivially will be cut off and replaced by primitive values.
diff --git a/java/com/google/gerrit/extensions/config/DownloadScheme.java b/java/com/google/gerrit/extensions/config/DownloadScheme.java
index d81657a..96b5878 100644
--- a/java/com/google/gerrit/extensions/config/DownloadScheme.java
+++ b/java/com/google/gerrit/extensions/config/DownloadScheme.java
@@ -26,12 +26,12 @@
*/
public abstract String getUrl(String project);
- /** @return whether this scheme requires authentication */
+ /** Returns whether this scheme requires authentication */
public abstract boolean isAuthRequired();
- /** @return whether this scheme supports authentication */
+ /** Returns whether this scheme supports authentication */
public abstract boolean isAuthSupported();
- /** @return whether the download scheme is enabled */
+ /** Returns whether the download scheme is enabled */
public abstract boolean isEnabled();
}
diff --git a/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java b/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java
index edb3e69..45c33c9 100644
--- a/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java
+++ b/java/com/google/gerrit/extensions/events/GarbageCollectorListener.java
@@ -22,8 +22,9 @@
public interface GarbageCollectorListener {
interface Event extends ProjectEvent {
/**
- * @return Properties describing the result of the garbage collection performed by JGit.
- * @see org.eclipse.jgit.api.GarbageCollectCommand#call()
+ * Returns properties describing the result of the garbage collection performed by JGit.
+ *
+ * <p>See {@link org.eclipse.jgit.api.GarbageCollectCommand#call }
*/
Properties getStatistics();
}
diff --git a/java/com/google/gerrit/extensions/restapi/BinaryResult.java b/java/com/google/gerrit/extensions/restapi/BinaryResult.java
index bdddfd9..2ee376e 100644
--- a/java/com/google/gerrit/extensions/restapi/BinaryResult.java
+++ b/java/com/google/gerrit/extensions/restapi/BinaryResult.java
@@ -63,7 +63,7 @@
private boolean base64;
private String attachmentName;
- /** @return the MIME type of the result, for HTTP clients. */
+ /** Returns the MIME type of the result, for HTTP clients. */
public String getContentType() {
Charset enc = getCharacterEncoding();
if (enc != null) {
@@ -100,7 +100,7 @@
return this;
}
- /** @return length in bytes of the result; -1 if not known. */
+ /** Returns length in bytes of the result; -1 if not known. */
public long getContentLength() {
return contentLength;
}
@@ -111,7 +111,7 @@
return this;
}
- /** @return true if this result can be gzip compressed to clients. */
+ /** Returns true if this result can be gzip compressed to clients. */
public boolean canGzip() {
return gzip;
}
@@ -122,7 +122,7 @@
return this;
}
- /** @return true if the result must be base64 encoded. */
+ /** Returns true if the result must be base64 encoded. */
public boolean isBase64() {
return base64;
}
diff --git a/java/com/google/gerrit/extensions/restapi/IdString.java b/java/com/google/gerrit/extensions/restapi/IdString.java
index 736c3ba..b2538fa 100644
--- a/java/com/google/gerrit/extensions/restapi/IdString.java
+++ b/java/com/google/gerrit/extensions/restapi/IdString.java
@@ -36,17 +36,17 @@
urlEncoded = s;
}
- /** @return the decoded value of the string. */
+ /** Returns the decoded value of the string. */
public String get() {
return Url.decode(urlEncoded);
}
- /** @return true if the string is the empty string. */
+ /** Returns true if the string is the empty string. */
public boolean isEmpty() {
return urlEncoded.isEmpty();
}
- /** @return the original URL encoding supplied by the client. */
+ /** Returns the original URL encoding supplied by the client. */
public String encoded() {
return urlEncoded;
}
diff --git a/java/com/google/gerrit/extensions/restapi/PreconditionFailedException.java b/java/com/google/gerrit/extensions/restapi/PreconditionFailedException.java
index b8c9d38..86b821b 100644
--- a/java/com/google/gerrit/extensions/restapi/PreconditionFailedException.java
+++ b/java/com/google/gerrit/extensions/restapi/PreconditionFailedException.java
@@ -22,4 +22,12 @@
public PreconditionFailedException(String msg) {
super(msg);
}
+
+ /**
+ * @param msg message to return to the client describing the error.
+ * @param cause cause of this exception.
+ */
+ public PreconditionFailedException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
}
diff --git a/java/com/google/gerrit/extensions/restapi/RestResource.java b/java/com/google/gerrit/extensions/restapi/RestResource.java
index cc5d48d..3c8144a 100644
--- a/java/com/google/gerrit/extensions/restapi/RestResource.java
+++ b/java/com/google/gerrit/extensions/restapi/RestResource.java
@@ -26,7 +26,7 @@
/** A resource with a last modification date. */
public interface HasLastModified {
- /** @return time for the Last-Modified header. HTTP truncates the header value to seconds. */
+ /** Returns time for the Last-Modified header. HTTP truncates the header value to seconds. */
Timestamp getLastModified();
}
diff --git a/java/com/google/gerrit/extensions/webui/WebUiPlugin.java b/java/com/google/gerrit/extensions/webui/WebUiPlugin.java
index 2d49e1c..4f129b0 100644
--- a/java/com/google/gerrit/extensions/webui/WebUiPlugin.java
+++ b/java/com/google/gerrit/extensions/webui/WebUiPlugin.java
@@ -44,7 +44,7 @@
private String pluginName;
- /** @return installed name of the plugin that provides this UI feature. */
+ /** Returns installed name of the plugin that provides this UI feature. */
public final String getPluginName() {
return pluginName;
}
@@ -54,7 +54,7 @@
this.pluginName = pluginName;
}
- /** @return path to initialization script within the plugin's JAR. */
+ /** Returns path to initialization script within the plugin's JAR. */
public abstract String getJavaScriptResourcePath();
@Override
diff --git a/java/com/google/gerrit/git/GitUpdateFailureException.java b/java/com/google/gerrit/git/GitUpdateFailureException.java
index 76ef217..7fcb828 100644
--- a/java/com/google/gerrit/git/GitUpdateFailureException.java
+++ b/java/com/google/gerrit/git/GitUpdateFailureException.java
@@ -46,12 +46,12 @@
.collect(toImmutableList());
}
- /** @return the names of the refs for which the update failed. */
+ /** Returns the names of the refs for which the update failed. */
public ImmutableList<String> getFailedRefs() {
return failures.stream().map(GitUpdateFailure::ref).collect(toImmutableList());
}
- /** @return the failures that caused this exception. */
+ /** Returns the failures that caused this exception. */
@UsedAt(UsedAt.Project.GOOGLE)
public ImmutableList<GitUpdateFailure> getFailures() {
return failures;
diff --git a/java/com/google/gerrit/gpg/CheckResult.java b/java/com/google/gerrit/gpg/CheckResult.java
index 8655b2a..2743e74 100644
--- a/java/com/google/gerrit/gpg/CheckResult.java
+++ b/java/com/google/gerrit/gpg/CheckResult.java
@@ -62,22 +62,22 @@
this.problems = problems;
}
- /** @return whether the result has status {@link Status#OK} or better. */
+ /** Returns whether the result has status {@link Status#OK} or better. */
public boolean isOk() {
return status.compareTo(Status.OK) >= 0;
}
- /** @return whether the result has status {@link Status#TRUSTED} or better. */
+ /** Returns whether the result has status {@link Status#TRUSTED} or better. */
public boolean isTrusted() {
return status.compareTo(Status.TRUSTED) >= 0;
}
- /** @return the status enum value associated with the object. */
+ /** Returns the status enum value associated with the object. */
public Status getStatus() {
return status;
}
- /** @return any problems encountered during checking. */
+ /** Returns any problems encountered during checking. */
public List<String> getProblems() {
return problems;
}
diff --git a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
index 9477cb6..71dff97 100644
--- a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
+++ b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
@@ -26,6 +26,7 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.query.account.InternalAccountQuery;
@@ -62,17 +63,20 @@
private final IdentifiedUser.GenericFactory userFactory;
private final int maxTrustDepth;
private final ImmutableMap<Long, Fingerprint> trusted;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
Factory(
@GerritServerConfig Config cfg,
Provider<InternalAccountQuery> accountQueryProvider,
IdentifiedUser.GenericFactory userFactory,
- DynamicItem<UrlFormatter> urlFormatter) {
+ DynamicItem<UrlFormatter> urlFormatter,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.accountQueryProvider = accountQueryProvider;
this.urlFormatter = urlFormatter;
this.userFactory = userFactory;
this.maxTrustDepth = cfg.getInt("receive", null, "maxTrustDepth", 0);
+ this.externalIdKeyFactory = externalIdKeyFactory;
String[] strs = cfg.getStringList("receive", null, "trustedKey");
if (strs.length != 0) {
@@ -103,6 +107,7 @@
private final Provider<InternalAccountQuery> accountQueryProvider;
private final DynamicItem<UrlFormatter> urlFormatter;
private final IdentifiedUser.GenericFactory userFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
private IdentifiedUser expectedUser;
@@ -113,6 +118,7 @@
if (factory.trusted != null) {
enableTrust(factory.maxTrustDepth, factory.trusted);
}
+ this.externalIdKeyFactory = factory.externalIdKeyFactory;
}
/**
@@ -247,7 +253,8 @@
return sb.toString();
}
- static ExternalId.Key toExtIdKey(PGPPublicKey key) {
- return ExternalId.Key.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(key.getFingerprint()));
+ ExternalId.Key toExtIdKey(PGPPublicKey key) {
+ return externalIdKeyFactory.create(
+ SCHEME_GPGKEY, BaseEncoding.base16().encode(key.getFingerprint()));
}
}
diff --git a/java/com/google/gerrit/gpg/PushCertificateChecker.java b/java/com/google/gerrit/gpg/PushCertificateChecker.java
index 82b3892..36a4af7 100644
--- a/java/com/google/gerrit/gpg/PushCertificateChecker.java
+++ b/java/com/google/gerrit/gpg/PushCertificateChecker.java
@@ -154,8 +154,11 @@
protected abstract Repository getRepository() throws IOException;
/**
+ * Specifies whether this repository should be closed before returning froms {@link
+ * #check(PushCertificate)}
+ *
* @param repo a repository previously returned by {@link #getRepository()}.
- * @return whether this repository should be closed before returning from {@link
+ * @return true if this repository should be closed before returning from {@link
* #check(PushCertificate)}.
*/
protected abstract boolean shouldClose(Repository repo);
diff --git a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
index 1be37f5..e0c921d 100644
--- a/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
+++ b/java/com/google/gerrit/gpg/server/DeleteGpgKey.java
@@ -32,6 +32,7 @@
import com.google.gerrit.server.UserInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.DeleteKeySender;
import com.google.inject.Inject;
@@ -53,6 +54,7 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final ExternalIds externalIds;
private final DeleteKeySender.Factory deleteKeySenderFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
DeleteGpgKey(
@@ -60,12 +62,14 @@
Provider<PublicKeyStore> storeProvider,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
ExternalIds externalIds,
- DeleteKeySender.Factory deleteKeySenderFactory) {
+ DeleteKeySender.Factory deleteKeySenderFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.serverIdent = serverIdent;
this.storeProvider = storeProvider;
this.accountsUpdateProvider = accountsUpdateProvider;
this.externalIds = externalIds;
this.deleteKeySenderFactory = deleteKeySenderFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -73,7 +77,8 @@
throws RestApiException, PGPException, IOException, ConfigInvalidException {
PGPPublicKey key = rsrc.getKeyRing().getPublicKey();
String fingerprint = BaseEncoding.base16().encode(key.getFingerprint());
- Optional<ExternalId> extId = externalIds.get(ExternalId.Key.create(SCHEME_GPGKEY, fingerprint));
+ Optional<ExternalId> extId =
+ externalIds.get(externalIdKeyFactory.create(SCHEME_GPGKEY, fingerprint));
if (!extId.isPresent()) {
throw new ResourceNotFoundException(fingerprint);
}
diff --git a/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index 1b5e06a..d46b344 100644
--- a/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -53,6 +53,8 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.AddKeySender;
import com.google.gerrit.server.mail.send.DeleteKeySender;
@@ -93,6 +95,8 @@
private final ExternalIds externalIds;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final RetryHelper retryHelper;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PostGpgKeys(
@@ -105,7 +109,9 @@
Provider<InternalAccountQuery> accountQueryProvider,
ExternalIds externalIds,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- RetryHelper retryHelper) {
+ RetryHelper retryHelper,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.serverIdent = serverIdent;
this.self = self;
this.storeProvider = storeProvider;
@@ -116,6 +122,8 @@
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.retryHelper = retryHelper;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -140,7 +148,7 @@
throw new ResourceConflictException("GPG key already associated with another account");
}
} else {
- newExtIds.add(ExternalId.create(extIdKey, rsrc.getUser().getAccountId()));
+ newExtIds.add(externalIdFactory.create(extIdKey, rsrc.getUser().getAccountId()));
}
}
@@ -287,7 +295,7 @@
}
private ExternalId.Key toExtIdKey(byte[] fp) {
- return ExternalId.Key.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(fp));
+ return externalIdKeyFactory.create(SCHEME_GPGKEY, BaseEncoding.base16().encode(fp));
}
private Account getAccountByExternalId(ExternalId.Key extIdKey) {
diff --git a/java/com/google/gerrit/gpg/testing/TestKeys.java b/java/com/google/gerrit/gpg/testing/TestKeys.java
index de66889..0423474 100644
--- a/java/com/google/gerrit/gpg/testing/TestKeys.java
+++ b/java/com/google/gerrit/gpg/testing/TestKeys.java
@@ -436,13 +436,13 @@
/**
* A key with an additional user ID.
*
- * <pre>
+ * <pre>{@code
* pub 2048R/98C51DBF 2015-07-30
* Key fingerprint = 42B3 294D 1924 D7EB AF4A A99F 5024 BB44 98C5 1DBF
* uid foo:myId
* uid Testuser Five <test5@example.com>
* sub 2048R/C781A9E3 2015-07-30
- * </pre>
+ * }</pre>
*/
public static TestKey validKeyWithSecondUserId() {
return new TestKey(
@@ -1033,13 +1033,13 @@
/**
* Master Key without expiration with subkey with expiration.
*
- * <pre>
+ * <pre>{@code
* pub rsa1024 2018-11-17 [C]
* 5734 2C37 982A 843B 19C0 622B 6AAF 2D26 B481 02DB
* uid [ultimate] Testuser 10 <testuser10@example.com>
* sub rsa1024 2018-11-17 [S] [expires: 2065-11-05]
* 0A4A 9660 1B96 2DFC E898 E686 4305 C92E 626E B485
- * </pre>
+ * }</pre>
*/
public static TestKey validKeyWithoutExpirationWithSubkeyWithExpiration() throws Exception {
return new TestKey(
diff --git a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
index de989ac..a421139 100644
--- a/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectBasicAuthFilter.java
@@ -76,17 +76,23 @@
private final AccountCache accountCache;
private final AccountManager accountManager;
private final AuthConfig authConfig;
+ private final AuthRequest.Factory authRequestFactory;
+ private final PasswordVerifier passwordVerifier;
@Inject
ProjectBasicAuthFilter(
DynamicItem<WebSession> session,
AccountCache accountCache,
AccountManager accountManager,
- AuthConfig authConfig) {
+ AuthConfig authConfig,
+ AuthRequest.Factory authRequestFactory,
+ PasswordVerifier passwordVerifier) {
this.session = session;
this.accountCache = accountCache;
this.accountManager = accountManager;
this.authConfig = authConfig;
+ this.authRequestFactory = authRequestFactory;
+ this.passwordVerifier = passwordVerifier;
}
@Override
@@ -155,7 +161,7 @@
GitBasicAuthPolicy gitBasicAuthPolicy = authConfig.getGitBasicAuthPolicy();
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP
|| gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP) {
- if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
+ if (passwordVerifier.checkPassword(who.externalIds(), username, password)) {
logger.atFine().log(
"HTTP:%s %s username/password authentication succeeded",
req.getMethod(), req.getRequestURI());
@@ -167,7 +173,7 @@
return failAuthentication(rsp, username, req);
}
- AuthRequest whoAuth = AuthRequest.forUser(username);
+ AuthRequest whoAuth = authRequestFactory.createForUser(username);
whoAuth.setPassword(password);
try {
@@ -177,7 +183,7 @@
"HTTP:%s %s Realm authentication succeeded", req.getMethod(), req.getRequestURI());
return true;
} catch (NoSuchUserException e) {
- if (PasswordVerifier.checkPassword(who.externalIds(), username, password)) {
+ if (passwordVerifier.checkPassword(who.externalIds(), username, password)) {
return succeedAuthentication(who, null);
}
logger.atWarning().withCause(e).log(authenticationFailedMsg(username, req));
diff --git a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
index dab36c4..fa53053 100644
--- a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
@@ -76,6 +76,7 @@
private final AccountManager accountManager;
private final String gitOAuthProvider;
private final boolean userNameToLowerCase;
+ private final AuthRequest.Factory authRequestFactory;
private String defaultAuthPlugin;
private String defaultAuthProvider;
@@ -86,13 +87,15 @@
DynamicMap<OAuthLoginProvider> pluginsProvider,
AccountCache accountCache,
AccountManager accountManager,
- @GerritServerConfig Config gerritConfig) {
+ @GerritServerConfig Config gerritConfig,
+ AuthRequest.Factory authRequestFactory) {
this.session = session;
this.loginProviders = pluginsProvider;
this.accountCache = accountCache;
this.accountManager = accountManager;
this.gitOAuthProvider = gerritConfig.getString("auth", null, "gitOAuthProvider");
this.userNameToLowerCase = gerritConfig.getBoolean("auth", null, "userNameToLowerCase", false);
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -162,7 +165,7 @@
}
Account account = who.get().account();
- AuthRequest authRequest = AuthRequest.forExternalUser(authInfo.username);
+ AuthRequest authRequest = authRequestFactory.createForExternalUser(authInfo.username);
authRequest.setEmailAddress(account.preferredEmail());
authRequest.setDisplayName(account.fullName());
authRequest.setPassword(authInfo.tokenOrSecret);
diff --git a/java/com/google/gerrit/httpd/RequestMetricsFilter.java b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
index c97b9ad..0ff1a79 100644
--- a/java/com/google/gerrit/httpd/RequestMetricsFilter.java
+++ b/java/com/google/gerrit/httpd/RequestMetricsFilter.java
@@ -55,17 +55,17 @@
startedMemory = threadMxBean.getCurrentThreadAllocatedBytes();
}
- /** @return total CPU time in milliseconds for executing request */
+ /** Returns total CPU time in milliseconds for executing request */
public long getTotalCpuTime() {
return (threadMxBean.getCurrentThreadCpuTime() - startedTotalCpu) / 1_000_000;
}
- /** @return CPU time in user mode in milliseconds for executing request */
+ /** Returns CPU time in user mode in milliseconds for executing request */
public long getUserCpuTime() {
return (threadMxBean.getCurrentThreadUserTime() - startedUserCpu) / 1_000_000;
}
- /** @return memory allocated in bytes for executing request */
+ /** Returns memory allocated in bytes for executing request */
public long getAllocatedMemory() {
return startedMemory == -1
? -1
diff --git a/java/com/google/gerrit/httpd/WebModule.java b/java/com/google/gerrit/httpd/WebModule.java
index e416075..0645aac 100644
--- a/java/com/google/gerrit/httpd/WebModule.java
+++ b/java/com/google/gerrit/httpd/WebModule.java
@@ -75,6 +75,10 @@
listener().toInstance(registerInParentInjectors());
install(UniversalWebLoginFilter.module());
+
+ // Static injection was unfortunately the best solution in this place. However, it is to be
+ // avoided if possible.
+ requestStaticInjection(WebSessionManager.Val.class);
}
private void installAuthModule() {
diff --git a/java/com/google/gerrit/httpd/WebSessionManager.java b/java/com/google/gerrit/httpd/WebSessionManager.java
index c0900ec..87bf3a6 100644
--- a/java/com/google/gerrit/httpd/WebSessionManager.java
+++ b/java/com/google/gerrit/httpd/WebSessionManager.java
@@ -32,6 +32,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.inject.Inject;
@@ -186,6 +187,8 @@
public static final class Val implements Serializable {
static final long serialVersionUID = 2L;
+ @Inject private static transient ExternalIdKeyFactory externalIdKeyFactory;
+
private transient Account.Id accountId;
private transient long refreshCookieAt;
private transient boolean persistentCookie;
@@ -295,7 +298,7 @@
persistentCookie = readVarInt32(in) != 0;
continue;
case 4:
- externalId = ExternalId.Key.parse(readString(in));
+ externalId = externalIdKeyFactory.parse(readString(in));
continue;
case 5:
sessionId = readString(in);
diff --git a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
index 97bb44b..2f760f0 100644
--- a/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/become/BecomeAnyAccountLoginServlet.java
@@ -31,7 +31,7 @@
import com.google.gerrit.server.account.Accounts;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.query.account.InternalAccountQuery;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.inject.Inject;
@@ -62,6 +62,8 @@
private final AccountManager accountManager;
private final SiteHeaderFooter headers;
private final Provider<InternalAccountQuery> queryProvider;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
BecomeAnyAccountLoginServlet(
@@ -70,13 +72,17 @@
AccountCache ac,
AccountManager am,
SiteHeaderFooter shf,
- Provider<InternalAccountQuery> qp) {
+ Provider<InternalAccountQuery> qp,
+ ExternalIdKeyFactory eikf,
+ AuthRequest.Factory arf) {
webSession = ws;
accounts = a;
accountCache = ac;
accountManager = am;
headers = shf;
queryProvider = qp;
+ externalIdKeyFactory = eikf;
+ authRequestFactory = arf;
}
@Override
@@ -220,7 +226,8 @@
private AuthResult create() throws IOException {
try {
return accountManager.authenticate(
- new AuthRequest(ExternalId.Key.create(SCHEME_UUID, UUID.randomUUID().toString())));
+ authRequestFactory.create(
+ externalIdKeyFactory.create(SCHEME_UUID, UUID.randomUUID().toString())));
} catch (AccountException e) {
getServletContext().log("cannot create new account", e);
return null;
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
index e20c9b9..acb3282 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpAuthFilter.java
@@ -26,6 +26,7 @@
import com.google.gerrit.httpd.RemoteUserUtil;
import com.google.gerrit.httpd.WebSession;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.gerrit.util.http.RequestUtil;
@@ -64,10 +65,16 @@
private final String emailHeader;
private final String externalIdHeader;
private final boolean userNameToLowerCase;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- HttpAuthFilter(DynamicItem<WebSession> webSession, AuthConfig authConfig) throws IOException {
+ HttpAuthFilter(
+ DynamicItem<WebSession> webSession,
+ AuthConfig authConfig,
+ ExternalIdKeyFactory externalIdKeyFactory)
+ throws IOException {
this.sessionProvider = webSession;
+ this.externalIdKeyFactory = externalIdKeyFactory;
final String pageName = "LoginRedirect.html";
final String doc = HtmlDomUtil.readFile(getClass(), pageName);
@@ -124,9 +131,9 @@
return false;
}
- private static boolean correctUser(String user, WebSession session) {
+ private boolean correctUser(String user, WebSession session) {
Optional<ExternalId.Key> id = session.getUser().getLastLoginExternalIdKey();
- return id.map(i -> i.equals(ExternalId.Key.create(SCHEME_GERRIT, user))).orElse(false);
+ return id.map(i -> i.equals(externalIdKeyFactory.create(SCHEME_GERRIT, user))).orElse(false);
}
String getRemoteUser(HttpServletRequest req) {
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
index 1b7e477..53f33b5 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpLoginServlet.java
@@ -28,7 +28,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.CacheHeaders;
import com.google.inject.Inject;
@@ -61,6 +61,8 @@
private final AccountManager accountManager;
private final HttpAuthFilter authFilter;
private final AuthConfig authConfig;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
HttpLoginServlet(
@@ -68,12 +70,16 @@
final CanonicalWebUrl urlProvider,
final AccountManager accountManager,
final HttpAuthFilter authFilter,
- final AuthConfig authConfig) {
+ final AuthConfig authConfig,
+ final ExternalIdKeyFactory externalIdKeyFactory,
+ final AuthRequest.Factory authRequestFactory) {
this.webSession = webSession;
this.urlProvider = urlProvider;
this.accountManager = accountManager;
this.authFilter = authFilter;
this.authConfig = authConfig;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -109,7 +115,7 @@
return;
}
- final AuthRequest areq = AuthRequest.forUser(user);
+ final AuthRequest areq = authRequestFactory.createForUser(user);
areq.setDisplayName(authFilter.getRemoteDisplayname(req));
areq.setEmailAddress(authFilter.getRemoteEmail(req));
final AuthResult arsp;
@@ -154,7 +160,7 @@
throws AccountException, IOException, ConfigInvalidException {
accountManager.updateLink(
arsp.getAccountId(),
- new AuthRequest(ExternalId.Key.create(SCHEME_EXTERNAL, remoteAuthToken)));
+ authRequestFactory.create(externalIdKeyFactory.create(SCHEME_EXTERNAL, remoteAuthToken)));
}
private void replace(Document doc, String name, String value) {
diff --git a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
index 40807c0..820c7a2 100644
--- a/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
+++ b/java/com/google/gerrit/httpd/auth/container/HttpsClientSslCertAuthFilter.java
@@ -42,12 +42,16 @@
private final DynamicItem<WebSession> webSession;
private final AccountManager accountManager;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
HttpsClientSslCertAuthFilter(
- final DynamicItem<WebSession> webSession, AccountManager accountManager) {
+ final DynamicItem<WebSession> webSession,
+ AccountManager accountManager,
+ final AuthRequest.Factory authRequestFactory) {
this.webSession = webSession;
this.accountManager = accountManager;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -70,7 +74,7 @@
} else {
throw new ServletException("Couldn't extract username from your certificate");
}
- final AuthRequest areq = AuthRequest.forUser(userName);
+ final AuthRequest areq = authRequestFactory.createForUser(userName);
final AuthResult arsp;
try {
arsp = accountManager.authenticate(areq);
diff --git a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
index a09866e..6caa760 100644
--- a/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
+++ b/java/com/google/gerrit/httpd/auth/ldap/LdapLoginServlet.java
@@ -56,17 +56,20 @@
private final DynamicItem<WebSession> webSession;
private final CanonicalWebUrl urlProvider;
private final SiteHeaderFooter headers;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
LdapLoginServlet(
AccountManager accountManager,
DynamicItem<WebSession> webSession,
CanonicalWebUrl urlProvider,
- SiteHeaderFooter headers) {
+ SiteHeaderFooter headers,
+ AuthRequest.Factory authRequestFactory) {
this.accountManager = accountManager;
this.webSession = webSession;
this.urlProvider = urlProvider;
this.headers = headers;
+ this.authRequestFactory = authRequestFactory;
}
private void sendForm(
@@ -115,7 +118,7 @@
return;
}
- AuthRequest areq = AuthRequest.forUser(username);
+ AuthRequest areq = authRequestFactory.createForUser(username);
areq.setPassword(password);
AuthResult ares;
diff --git a/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java b/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
index 70ed79b..a3f8fbda 100644
--- a/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
+++ b/java/com/google/gerrit/httpd/auth/oauth/OAuthSession.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.servlet.SessionScoped;
@@ -65,6 +65,8 @@
private Account.Id accountId;
private String redirectToken;
private boolean linkMode;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
OAuthSession(
@@ -72,13 +74,17 @@
Provider<IdentifiedUser> identifiedUser,
AccountManager accountManager,
CanonicalWebUrl urlProvider,
- OAuthTokenCache tokenCache) {
+ OAuthTokenCache tokenCache,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ AuthRequest.Factory authRequestFactory) {
this.state = generateRandomState();
this.identifiedUser = identifiedUser;
this.webSession = webSession;
this.accountManager = accountManager;
this.urlProvider = urlProvider;
this.tokenCache = tokenCache;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
boolean isLoggedIn() {
@@ -126,7 +132,7 @@
private void authenticateAndRedirect(
HttpServletRequest req, HttpServletResponse rsp, OAuthToken token) throws IOException {
- AuthRequest areq = new AuthRequest(ExternalId.Key.parse(user.getExternalId()));
+ AuthRequest areq = authRequestFactory.create(externalIdKeyFactory.parse(user.getExternalId()));
AuthResult arsp;
try {
String claimedIdentifier = user.getClaimedIdentity();
diff --git a/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java b/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
index b987c68..df0062c 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OAuthSessionOverOpenID.java
@@ -32,8 +32,9 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.servlet.SessionScoped;
@@ -63,18 +64,24 @@
private OAuthUserInfo user;
private String redirectToken;
private boolean linkMode;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
OAuthSessionOverOpenID(
DynamicItem<WebSession> webSession,
Provider<IdentifiedUser> identifiedUser,
AccountManager accountManager,
- CanonicalWebUrl urlProvider) {
+ CanonicalWebUrl urlProvider,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ AuthRequest.Factory authRequestFactory) {
this.state = generateRandomState();
this.webSession = webSession;
this.identifiedUser = identifiedUser;
this.accountManager = accountManager;
this.urlProvider = urlProvider;
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
boolean isLoggedIn() {
@@ -117,8 +124,7 @@
private void authenticateAndRedirect(HttpServletRequest req, HttpServletResponse rsp)
throws IOException {
com.google.gerrit.server.account.AuthRequest areq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(user.getExternalId()));
+ authRequestFactory.create(externalIdKeyFactory.parse(user.getExternalId()));
AuthResult arsp;
try {
String claimedIdentifier = user.getClaimedIdentity();
diff --git a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
index b685011..cf3562f 100644
--- a/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
+++ b/java/com/google/gerrit/httpd/auth/openid/OpenIdServiceImpl.java
@@ -28,7 +28,7 @@
import com.google.gerrit.server.UrlEncoded;
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.auth.openid.OpenIdProviderPattern;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.ConfigUtil;
@@ -92,6 +92,8 @@
private final ConsumerManager manager;
private final List<OpenIdProviderPattern> allowedOpenIDs;
private final List<String> openIdDomains;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+ private final com.google.gerrit.server.account.AuthRequest.Factory authRequestFactory;
/** Maximum age, in seconds, before forcing re-authentication of account. */
private final int papeMaxAuthAge;
@@ -104,7 +106,9 @@
@GerritServerConfig Config config,
AuthConfig ac,
AccountManager am,
- ProxyProperties proxyProperties) {
+ ProxyProperties proxyProperties,
+ ExternalIdKeyFactory externalIdKeyFactory,
+ com.google.gerrit.server.account.AuthRequest.Factory authRequestFactory) {
if (proxyProperties.getProxyUrl() != null) {
final org.openid4java.util.ProxyProperties proxy = new org.openid4java.util.ProxyProperties();
@@ -132,6 +136,8 @@
"maxOpenIdSessionAge",
-1,
TimeUnit.SECONDS);
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ this.authRequestFactory = authRequestFactory;
}
@SuppressWarnings("unchecked")
@@ -310,7 +316,7 @@
}
final com.google.gerrit.server.account.AuthRequest areq =
- new com.google.gerrit.server.account.AuthRequest(ExternalId.Key.parse(openidIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(openidIdentifier));
if (sregRsp != null) {
areq.setDisplayName(sregRsp.getAttributeValue("fullname"));
@@ -388,8 +394,7 @@
// was missing due to a bug in Gerrit. Link the claimed.
//
final com.google.gerrit.server.account.AuthRequest linkReq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(claimedIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(claimedIdentifier));
linkReq.setDisplayName(areq.getDisplayName());
linkReq.setEmailAddress(areq.getEmailAddress());
accountManager.link(actualId.get(), linkReq);
@@ -425,8 +430,7 @@
webSession.get().login(arsp, remember);
if (arsp.isNew() && claimedIdentifier != null) {
final com.google.gerrit.server.account.AuthRequest linkReq =
- new com.google.gerrit.server.account.AuthRequest(
- ExternalId.Key.parse(claimedIdentifier));
+ authRequestFactory.create(externalIdKeyFactory.parse(claimedIdentifier));
linkReq.setDisplayName(areq.getDisplayName());
linkReq.setEmailAddress(areq.getEmailAddress());
accountManager.link(arsp.getAccountId(), linkReq);
diff --git a/java/com/google/gerrit/httpd/restapi/ParameterParser.java b/java/com/google/gerrit/httpd/restapi/ParameterParser.java
index 3ab409e..315c9c8 100644
--- a/java/com/google/gerrit/httpd/restapi/ParameterParser.java
+++ b/java/com/google/gerrit/httpd/restapi/ParameterParser.java
@@ -56,9 +56,18 @@
public class ParameterParser {
public static final String TRACE_PARAMETER = "trace";
+ public static final String EXPERIMENT_PARAMETER = "experiment";
private static final ImmutableSet<String> RESERVED_KEYS =
- ImmutableSet.of("pp", "prettyPrint", "strict", "callback", "alt", "fields", TRACE_PARAMETER);
+ ImmutableSet.of(
+ "pp",
+ "prettyPrint",
+ "strict",
+ "callback",
+ "alt",
+ "fields",
+ TRACE_PARAMETER,
+ EXPERIMENT_PARAMETER);
@AutoValue
public abstract static class QueryParams {
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index c65d0b5..369ea29 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -359,15 +359,11 @@
ViewData viewData = null;
try (TraceContext traceContext = enableTracing(req, res)) {
- List<IdString> path = splitPath(req);
- RequestInfo requestInfo = createRequestInfo(traceContext, requestUri(req), path);
+ String requestUri = requestUri(req);
- try (RequestStateContext requestStateContext =
- RequestStateContext.open()
- .addRequestStateProvider(
- globals.deadlineCheckerFactory.create(
- requestInfo, req.getHeader(X_GERRIT_DEADLINE)));
- PerThreadCache ignored = PerThreadCache.create()) {
+ try (PerThreadCache ignored = PerThreadCache.create()) {
+ List<IdString> path = splitPath(req);
+ RequestInfo requestInfo = createRequestInfo(traceContext, requestUri, path);
globals.requestListeners.runEach(l -> l.onRequest(requestInfo));
// It's important that the PerformanceLogContext is closed before the response is sent to
@@ -375,8 +371,13 @@
// plugins happens before the client sees the response. This is needed for being able to
// test performance logging from an acceptance test (see
// TraceIT#performanceLoggingForRestCall()).
- try (PerformanceLogContext performanceLogContext =
- new PerformanceLogContext(globals.config, globals.performanceLoggers)) {
+ try (RequestStateContext requestStateContext =
+ RequestStateContext.open()
+ .addRequestStateProvider(
+ globals.deadlineCheckerFactory.create(
+ requestInfo, req.getHeader(X_GERRIT_DEADLINE)));
+ PerformanceLogContext performanceLogContext =
+ new PerformanceLogContext(globals.config, globals.performanceLoggers)) {
traceRequestData(req);
if (isCorsPreflight(req)) {
@@ -741,7 +742,8 @@
if (requestCancelledException.isPresent()) {
RequestStateProvider.Reason cancellationReason =
requestCancelledException.get().getCancellationReason();
- globals.cancellationMetrics.countCancelledRequest(requestInfo, cancellationReason);
+ globals.cancellationMetrics.countCancelledRequest(
+ RequestInfo.RequestType.REST, requestUri, cancellationReason);
statusCode = getCancellationStatusCode(cancellationReason);
responseBytes =
replyError(
@@ -766,13 +768,12 @@
}
} else {
res.reset();
- traceContext.getTraceId().ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
+ TraceContext.getTraceId().ifPresent(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
if (status.isPresent()) {
- responseBytes = reply(req, res, e, status.get(), getUserMessages(traceContext, e));
+ responseBytes = reply(req, res, e, status.get(), getUserMessages(e));
} else {
- responseBytes =
- replyInternalServerError(req, res, e, getUserMessages(traceContext, e));
+ responseBytes = replyInternalServerError(req, res, e, getUserMessages(e));
}
}
}
@@ -982,7 +983,7 @@
throws Exception {
RetryableAction<T> retryableAction = globals.retryHelper.action(actionType, caller, action);
AtomicReference<Optional<String>> traceId = new AtomicReference<>(Optional.empty());
- if (!traceContext.isTracing()) {
+ if (!TraceContext.isTracing()) {
// enable automatic retry with tracing in case of non-recoverable failure
retryableAction
.retryWithTrace(t -> !(t instanceof RestApiException))
@@ -1425,7 +1426,6 @@
* @param config config parameters for the JSON formatting
* @param result the object that should be formatted as JSON
* @return the length of the response
- * @throws IOException
*/
public static long replyJson(
@Nullable HttpServletRequest req,
@@ -1815,6 +1815,10 @@
logger.atFinest().log(
"Received REST request: %s %s (parameters: %s)",
req.getMethod(), req.getRequestURI(), getParameterNames(req));
+ Optional.ofNullable(req.getHeader(X_GERRIT_DEADLINE))
+ .ifPresent(
+ clientProvidedDeadline ->
+ logger.atFine().log("%s = %s", X_GERRIT_DEADLINE, clientProvidedDeadline));
logger.atFinest().log("Calling user: %s", globals.currentUser.get().getLoggableName());
logger.atFinest().log(
"Groups: %s", lazy(() -> globals.currentUser.get().getEffectiveGroups().getKnownGroups()));
@@ -1870,9 +1874,9 @@
.findFirst();
}
- private ImmutableList<String> getUserMessages(TraceContext traceContext, Throwable err) {
+ private ImmutableList<String> getUserMessages(Throwable err) {
return globals.exceptionHooks.stream()
- .flatMap(h -> h.getUserMessages(err, traceContext.getTraceId().orElse(null)).stream())
+ .flatMap(h -> h.getUserMessages(err, TraceContext.getTraceId().orElse(null)).stream())
.collect(toImmutableList());
}
@@ -1965,7 +1969,6 @@
* set to {@code true} if the reply may contain sensitive data
* @param text the text reply
* @return the length of the response
- * @throws IOException
*/
static long replyText(
@Nullable HttpServletRequest req, HttpServletResponse res, boolean allowTracing, String text)
diff --git a/java/com/google/gerrit/index/FieldDef.java b/java/com/google/gerrit/index/FieldDef.java
index eb64c1d..76aa7cc 100644
--- a/java/com/google/gerrit/index/FieldDef.java
+++ b/java/com/google/gerrit/index/FieldDef.java
@@ -138,17 +138,17 @@
return name;
}
- /** @return name of the field. */
+ /** Returns name of the field. */
public String getName() {
return name;
}
- /** @return type of the field; for repeatable fields, the inner type, not the iterable type. */
+ /** Returns type of the field; for repeatable fields, the inner type, not the iterable type. */
public FieldType<?> getType() {
return type;
}
- /** @return whether the field should be stored in the index. */
+ /** Returns whether the field should be stored in the index. */
public boolean isStored() {
return stored;
}
@@ -203,7 +203,7 @@
return false;
}
- /** @return whether the field is repeatable. */
+ /** Returns whether the field is repeatable. */
public boolean isRepeatable() {
return repeatable;
}
diff --git a/java/com/google/gerrit/index/Index.java b/java/com/google/gerrit/index/Index.java
index 529cd78..ead302d 100644
--- a/java/com/google/gerrit/index/Index.java
+++ b/java/com/google/gerrit/index/Index.java
@@ -33,7 +33,7 @@
* <p>Implementations must be thread-safe and should batch inserts/updates where appropriate.
*/
public interface Index<K, V> {
- /** @return the schema version used by this index. */
+ /** Returns the schema version used by this index. */
Schema<V> getSchema();
/** Close this index. */
diff --git a/java/com/google/gerrit/index/IndexConfig.java b/java/com/google/gerrit/index/IndexConfig.java
index 29b8ea6..8676fb2 100644
--- a/java/com/google/gerrit/index/IndexConfig.java
+++ b/java/com/google/gerrit/index/IndexConfig.java
@@ -101,27 +101,27 @@
}
/**
- * @return maximum limit supported by the underlying index, or limited for performance reasons.
+ * Returns maximum limit supported by the underlying index, or limited for performance reasons.
*/
public abstract int maxLimit();
/**
- * @return maximum number of pages (limit / start) supported by the underlying index, or limited
- * for performance reasons.
+ * Returns maximum number of pages (limit / start) supported by the underlying index, or limited
+ * for performance reasons.
*/
public abstract int maxPages();
/**
- * @return maximum number of total index query terms supported by the underlying index, or limited
- * for performance reasons.
+ * Returns maximum number of total index query terms supported by the underlying index, or limited
+ * for performance reasons.
*/
public abstract int maxTerms();
- /** @return index type. */
+ /** Returns index type. */
public abstract String type();
/**
- * @return whether different subsets of changes may be stored in different physical sub-indexes.
+ * Returns whether different subsets of changes may be stored in different physical sub-indexes.
*/
public abstract boolean separateChangeSubIndexes();
}
diff --git a/java/com/google/gerrit/index/Schema.java b/java/com/google/gerrit/index/Schema.java
index 3aa9de0..91c3f70 100644
--- a/java/com/google/gerrit/index/Schema.java
+++ b/java/com/google/gerrit/index/Schema.java
@@ -134,7 +134,7 @@
return fields;
}
- /** @return all fields in this schema where {@link FieldDef#isStored()} is true. */
+ /** Returns all fields in this schema where {@link FieldDef#isStored()} is true. */
public final ImmutableMap<String, FieldDef<T, ?>> getStoredFields() {
return storedFields;
}
diff --git a/java/com/google/gerrit/index/query/DataSource.java b/java/com/google/gerrit/index/query/DataSource.java
index 2c2ba53..518d153 100644
--- a/java/com/google/gerrit/index/query/DataSource.java
+++ b/java/com/google/gerrit/index/query/DataSource.java
@@ -15,12 +15,12 @@
package com.google.gerrit.index.query;
public interface DataSource<T> {
- /** @return an estimate of the number of results from {@link #read()}. */
+ /** Returns an estimate of the number of results from {@link #read()}. */
int getCardinality();
- /** @return read from the database and return the results. */
+ /** Returns read from the database and return the results. */
ResultSet<T> read();
- /** @return read from the database and return the raw results. */
+ /** Returns read from the database and return the raw results. */
ResultSet<FieldBundle> readRaw();
}
diff --git a/java/com/google/gerrit/index/query/Matchable.java b/java/com/google/gerrit/index/query/Matchable.java
index 7a16ae8..f416149 100644
--- a/java/com/google/gerrit/index/query/Matchable.java
+++ b/java/com/google/gerrit/index/query/Matchable.java
@@ -18,6 +18,6 @@
/** Does this predicate match this object? */
boolean match(T object);
- /** @return a cost estimate to run this predicate, higher figures cost more. */
+ /** Returns a cost estimate to run this predicate, higher figures cost more. */
int getCost();
}
diff --git a/java/com/google/gerrit/index/query/Predicate.java b/java/com/google/gerrit/index/query/Predicate.java
index 2382d30..2791f2c 100644
--- a/java/com/google/gerrit/index/query/Predicate.java
+++ b/java/com/google/gerrit/index/query/Predicate.java
@@ -159,7 +159,7 @@
return (Matchable<T>) this;
}
- /** @return a cost estimate to run this predicate, higher figures cost more. */
+ /** Returns a cost estimate to run this predicate, higher figures cost more. */
public int estimateCost() {
if (!isMatchable()) {
return 1;
diff --git a/java/com/google/gerrit/index/query/QueryResult.java b/java/com/google/gerrit/index/query/QueryResult.java
index 33fcef0..d03a68b 100644
--- a/java/com/google/gerrit/index/query/QueryResult.java
+++ b/java/com/google/gerrit/index/query/QueryResult.java
@@ -34,19 +34,19 @@
return new AutoValue_QueryResult<>(query, predicate, ImmutableList.copyOf(entities), more);
}
- /** @return the original query string, or null if the query was created programmatically. */
+ /** Returns the original query string, or null if the query was created programmatically. */
@Nullable
public abstract String query();
- /** @return the predicate after all rewriting and other modification by the query subsystem. */
+ /** Returns the predicate after all rewriting and other modification by the query subsystem. */
public abstract Predicate<T> predicate();
- /** @return the query results. */
+ /** Returns the query results. */
public abstract ImmutableList<T> entities();
/**
- * @return whether the query could be retried with a higher start/limit to produce more results.
- * Never true if {@link #entities()} is empty.
+ * Returns whether the query could be retried with a higher start/limit to produce more results.
+ * Never true if {@link #entities()} is empty.
*/
public abstract boolean more();
}
diff --git a/java/com/google/gerrit/json/OutputFormat.java b/java/com/google/gerrit/json/OutputFormat.java
index 3e7c319..c5504bb 100644
--- a/java/com/google/gerrit/json/OutputFormat.java
+++ b/java/com/google/gerrit/json/OutputFormat.java
@@ -42,12 +42,12 @@
*/
JSON_COMPACT;
- /** @return true when the format is either JSON or JSON_COMPACT. */
+ /** Returns true when the format is either JSON or JSON_COMPACT. */
public boolean isJson() {
return this == JSON_COMPACT || this == JSON;
}
- /** @return a new Gson instance configured according to the format. */
+ /** Returns a new Gson instance configured according to the format. */
public GsonBuilder newGsonBuilder() {
if (!isJson()) {
throw new IllegalStateException(String.format("%s is not JSON", this));
@@ -63,7 +63,7 @@
return gb;
}
- /** @return a new Gson instance configured according to the format. */
+ /** Returns a new Gson instance configured according to the format. */
public Gson newGson() {
return newGsonBuilder().create();
}
diff --git a/java/com/google/gerrit/lifecycle/LifecycleModule.java b/java/com/google/gerrit/lifecycle/LifecycleModule.java
index 0fb4653..efe1518 100644
--- a/java/com/google/gerrit/lifecycle/LifecycleModule.java
+++ b/java/com/google/gerrit/lifecycle/LifecycleModule.java
@@ -24,13 +24,16 @@
/** Module to support registering a unique LifecyleListener. */
public abstract class LifecycleModule extends FactoryModule {
/**
- * @return a unique listener binding.
- * <p>To create a listener binding use:
- * <pre>
+ * Returns a unique listener binding.
+ *
+ * <p>To create a listener binding use:
+ *
+ * <pre>
* listener().to(MyListener.class);
* </pre>
- * where {@code MyListener} is a {@link Singleton} implementing the {@link LifecycleListener}
- * interface.
+ *
+ * where {@code MyListener} is a {@link Singleton} implementing the {@link LifecycleListener}
+ * interface.
*/
protected LinkedBindingBuilder<LifecycleListener> listener() {
final Annotation id = UniqueAnnotations.create();
diff --git a/java/com/google/gerrit/mail/HtmlParser.java b/java/com/google/gerrit/mail/HtmlParser.java
index ba73bdd..97fe06e 100644
--- a/java/com/google/gerrit/mail/HtmlParser.java
+++ b/java/com/google/gerrit/mail/HtmlParser.java
@@ -143,7 +143,7 @@
if (!Strings.isNullOrEmpty(content)) {
ParserUtil.appendOrAddNewComment(
new MailComment(
- content, null, null, MailComment.CommentType.CHANGE_MESSAGE, isLink),
+ content, null, null, MailComment.CommentType.PATCHSET_LEVEL, isLink),
parsedComments);
}
} else if (lastEncounteredComment == null) {
diff --git a/java/com/google/gerrit/mail/MailComment.java b/java/com/google/gerrit/mail/MailComment.java
index 3e7da10..cea856c 100644
--- a/java/com/google/gerrit/mail/MailComment.java
+++ b/java/com/google/gerrit/mail/MailComment.java
@@ -20,7 +20,7 @@
/** A comment parsed from inbound email */
public class MailComment {
public enum CommentType {
- CHANGE_MESSAGE,
+ PATCHSET_LEVEL,
FILE_COMMENT,
INLINE_COMMENT
}
diff --git a/java/com/google/gerrit/mail/TextParser.java b/java/com/google/gerrit/mail/TextParser.java
index a33c66f..c43d200 100644
--- a/java/com/google/gerrit/mail/TextParser.java
+++ b/java/com/google/gerrit/mail/TextParser.java
@@ -30,7 +30,7 @@
/**
* Parses comments from plaintext email.
*
- * @param email @param email the message as received from the email service
+ * @param email the message as received from the email service
* @param comments list of {@link HumanComment}s previously persisted on the change that caused
* the original notification email to be sent out. Ordering must be the same as in the
* outbound email
@@ -77,7 +77,7 @@
// This is not a comment, try to advance the file/comment pointers and
// add previous comment to list if applicable
if (currentComment != null) {
- if (currentComment.type == MailComment.CommentType.CHANGE_MESSAGE) {
+ if (currentComment.type == MailComment.CommentType.PATCHSET_LEVEL) {
currentComment.message = ParserUtil.trimQuotation(currentComment.message);
}
if (!Strings.isNullOrEmpty(currentComment.message)) {
@@ -115,7 +115,7 @@
if (lastEncounteredComment == null) {
if (lastEncounteredFileName == null) {
// Change message
- currentComment.type = MailComment.CommentType.CHANGE_MESSAGE;
+ currentComment.type = MailComment.CommentType.PATCHSET_LEVEL;
} else {
// File comment not sent in reply to another comment
currentComment.type = MailComment.CommentType.FILE_COMMENT;
diff --git a/java/com/google/gerrit/metrics/BUILD b/java/com/google/gerrit/metrics/BUILD
index 3cc056b..0cb0275 100644
--- a/java/com/google/gerrit/metrics/BUILD
+++ b/java/com/google/gerrit/metrics/BUILD
@@ -8,6 +8,7 @@
"//java/com/google/gerrit/common:server",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/lifecycle",
+ "//java/com/google/gerrit/server/cancellation",
"//java/com/google/gerrit/server/logging",
"//lib:guava",
"//lib:jgit",
diff --git a/java/com/google/gerrit/metrics/Description.java b/java/com/google/gerrit/metrics/Description.java
index 10568bc..f5963af 100644
--- a/java/com/google/gerrit/metrics/Description.java
+++ b/java/com/google/gerrit/metrics/Description.java
@@ -133,27 +133,27 @@
return this;
}
- /** @return true if the metric value never changes after startup. */
+ /** Returns true if the metric value never changes after startup. */
public boolean isConstant() {
return TRUE_VALUE.equals(annotations.get(CONSTANT));
}
- /** @return true if the metric may be interpreted as a rate over time. */
+ /** Returns true if the metric may be interpreted as a rate over time. */
public boolean isRate() {
return TRUE_VALUE.equals(annotations.get(RATE));
}
- /** @return true if the metric is an instantaneous sample. */
+ /** Returns true if the metric is an instantaneous sample. */
public boolean isGauge() {
return TRUE_VALUE.equals(annotations.get(GAUGE));
}
- /** @return true if the metric accumulates over the lifespan of the process. */
+ /** Returns true if the metric accumulates over the lifespan of the process. */
public boolean isCumulative() {
return TRUE_VALUE.equals(annotations.get(CUMULATIVE));
}
- /** @return the suggested field ordering. */
+ /** Returns the suggested field ordering. */
public FieldOrdering getFieldOrdering() {
String o = annotations.get(FIELD_ORDERING);
return o != null ? FieldOrdering.valueOf(o) : FieldOrdering.AT_END;
@@ -187,7 +187,7 @@
return u;
}
- /** @return immutable copy of all annotations (configurable properties). */
+ /** Returns an immutable copy of all annotations (configurable properties). */
public ImmutableMap<String, String> getAnnotations() {
return ImmutableMap.copyOf(annotations);
}
diff --git a/java/com/google/gerrit/metrics/Field.java b/java/com/google/gerrit/metrics/Field.java
index bdae854..5508819 100644
--- a/java/com/google/gerrit/metrics/Field.java
+++ b/java/com/google/gerrit/metrics/Field.java
@@ -102,19 +102,19 @@
.metadataMapper(metadataMapper);
}
- /** @return name of this field within the metric. */
+ /** Returns name of this field within the metric. */
public abstract String name();
- /** @return type of value used within the field. */
+ /** Returns type of value used within the field. */
public abstract Class<T> valueType();
- /** @return mapper that maps a field value to a field in the {@link Metadata} class. */
+ /** Returns mapper that maps a field value to a field in the {@link Metadata} class. */
public abstract BiConsumer<Metadata.Builder, T> metadataMapper();
- /** @return description text for the field explaining its range of values. */
+ /** Returns description text for the field explaining its range of values. */
public abstract Optional<String> description();
- /** @return formatter to format field values. */
+ /** Returns formatter to format field values. */
public abstract Function<T, String> formatter();
@AutoValue.Builder
diff --git a/java/com/google/gerrit/metrics/Timer0.java b/java/com/google/gerrit/metrics/Timer0.java
index d0033a4..2617431 100644
--- a/java/com/google/gerrit/metrics/Timer0.java
+++ b/java/com/google/gerrit/metrics/Timer0.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.server.cancellation.RequestStateContext;
import com.google.gerrit.server.logging.LoggingContext;
import com.google.gerrit.server.logging.PerformanceLogRecord;
import java.util.concurrent.TimeUnit;
@@ -60,6 +61,7 @@
* @return timer context
*/
public Context start() {
+ RequestStateContext.abortIfCancelled();
return new Context(this);
}
@@ -75,6 +77,7 @@
.addPerformanceLogRecord(() -> PerformanceLogRecord.create(name, durationMs));
logger.atFinest().log("%s took %dms", name, durationMs);
doRecord(value, unit);
+ RequestStateContext.abortIfCancelled();
}
/**
diff --git a/java/com/google/gerrit/metrics/Timer1.java b/java/com/google/gerrit/metrics/Timer1.java
index a8fb1a2..319f3e0 100644
--- a/java/com/google/gerrit/metrics/Timer1.java
+++ b/java/com/google/gerrit/metrics/Timer1.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.server.cancellation.RequestStateContext;
import com.google.gerrit.server.logging.LoggingContext;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.PerformanceLogRecord;
@@ -68,6 +69,7 @@
* @return timer context
*/
public Context<F1> start(F1 fieldValue) {
+ RequestStateContext.abortIfCancelled();
return new Context<>(this, fieldValue);
}
@@ -90,6 +92,7 @@
logger.atFinest().log("%s (%s = %s) took %dms", name, field.name(), fieldValue, durationMs);
doRecord(fieldValue, value, unit);
+ RequestStateContext.abortIfCancelled();
}
/**
diff --git a/java/com/google/gerrit/metrics/Timer2.java b/java/com/google/gerrit/metrics/Timer2.java
index 8a4a793..8ae76a2 100644
--- a/java/com/google/gerrit/metrics/Timer2.java
+++ b/java/com/google/gerrit/metrics/Timer2.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.server.cancellation.RequestStateContext;
import com.google.gerrit.server.logging.LoggingContext;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.PerformanceLogRecord;
@@ -74,6 +75,7 @@
* @return timer context
*/
public Context<F1, F2> start(F1 fieldValue1, F2 fieldValue2) {
+ RequestStateContext.abortIfCancelled();
return new Context<>(this, fieldValue1, fieldValue2);
}
@@ -100,6 +102,7 @@
"%s (%s = %s, %s = %s) took %dms",
name, field1.name(), fieldValue1, field2.name(), fieldValue2, durationMs);
doRecord(fieldValue1, fieldValue2, value, unit);
+ RequestStateContext.abortIfCancelled();
}
/**
diff --git a/java/com/google/gerrit/metrics/Timer3.java b/java/com/google/gerrit/metrics/Timer3.java
index 2044da6..9df963a 100644
--- a/java/com/google/gerrit/metrics/Timer3.java
+++ b/java/com/google/gerrit/metrics/Timer3.java
@@ -18,6 +18,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.RegistrationHandle;
+import com.google.gerrit.server.cancellation.RequestStateContext;
import com.google.gerrit.server.logging.LoggingContext;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.PerformanceLogRecord;
@@ -80,6 +81,7 @@
* @return timer context
*/
public Context<F1, F2, F3> start(F1 fieldValue1, F2 fieldValue2, F3 fieldValue3) {
+ RequestStateContext.abortIfCancelled();
return new Context<>(this, fieldValue1, fieldValue2, fieldValue3);
}
@@ -116,6 +118,7 @@
fieldValue3,
durationMs);
doRecord(fieldValue1, fieldValue2, fieldValue3, value, unit);
+ RequestStateContext.abortIfCancelled();
}
/**
diff --git a/java/com/google/gerrit/metrics/TimerContext.java b/java/com/google/gerrit/metrics/TimerContext.java
index 62eb030..a3754c5 100644
--- a/java/com/google/gerrit/metrics/TimerContext.java
+++ b/java/com/google/gerrit/metrics/TimerContext.java
@@ -29,7 +29,7 @@
*/
public abstract void record(long elapsed);
- /** @return the start time in system time nanoseconds. */
+ /** Returns the start time in system time nanoseconds. */
public long getStartTime() {
return startNanos;
}
diff --git a/java/com/google/gerrit/metrics/proc/JGitMetricModule.java b/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
index e8611b3..d64bd19 100644
--- a/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
+++ b/java/com/google/gerrit/metrics/proc/JGitMetricModule.java
@@ -184,7 +184,9 @@
+ "having most data in the cache.")
.setGauge()
.setUnit("byte"),
- Field.ofString("repository_name", Metadata.Builder::projectName).build());
+ Field.ofString("repository_name", Metadata.Builder::projectName)
+ .description("The name of the repository.")
+ .build());
metrics.newTrigger(
repoEnt,
() -> {
diff --git a/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java b/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java
new file mode 100644
index 0000000..01c76c1
--- /dev/null
+++ b/java/com/google/gerrit/pgm/ChangeExternalIdCaseSensitivity.java
@@ -0,0 +1,202 @@
+// 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.pgm;
+
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.exceptions.DuplicateKeyException;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.lifecycle.LifecycleManager;
+import com.google.gerrit.pgm.init.api.ConsoleUI;
+import com.google.gerrit.pgm.util.SiteProgram;
+import com.google.gerrit.server.account.externalids.DisabledExternalIdCache;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdNotes;
+import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
+import com.google.gerrit.server.account.externalids.ExternalIds;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
+import com.google.gerrit.server.schema.NoteDbSchemaVersionCheck;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import java.io.IOException;
+import java.util.Collection;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.kohsuke.args4j.Option;
+
+/**
+ * Changes the case sensitivity of `username:` and `gerrit:` external IDs by recomputing the SHA-1
+ * sums used as note names.
+ */
+public class ChangeExternalIdCaseSensitivity extends SiteProgram {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ @Option(name = "--batch", usage = "Don't ask for confirmation before migrating.")
+ private boolean batch;
+
+ @Option(name = "--dryrun", usage = "Do a dryrun of the migration.")
+ private boolean dryrun;
+
+ private final LifecycleManager manager = new LifecycleManager();
+ private final TextProgressMonitor monitor = new TextProgressMonitor();
+
+ private Config globalConfig;
+ private boolean isUserNameCaseInsensitive;
+ private ConsoleUI ui;
+
+ @Inject private GitRepositoryManager repoManager;
+ @Inject private AllUsersName allUsersName;
+ @Inject private Provider<MetaDataUpdate.Server> metaDataUpdateServerFactory;
+ @Inject private ExternalIdNotes.FactoryNoReindex externalIdNotesFactory;
+ @Inject private ExternalIds externalIds;
+ @Inject private ExternalIdFactory externalIdFactory;
+
+ @Override
+ public int run() throws Exception {
+ mustHaveValidSite();
+ ui = ConsoleUI.getInstance(batch);
+
+ Injector dbInjector = createDbInjector();
+ manager.add(dbInjector, dbInjector.createChildInjector(NoteDbSchemaVersionCheck.module()));
+ dbInjector
+ .createChildInjector(
+ new FactoryModule() {
+ @Override
+ protected void configure() {
+ bind(GitReferenceUpdated.class).toInstance(GitReferenceUpdated.DISABLED);
+ factory(MetaDataUpdate.InternalFactory.class);
+ DynamicMap.mapOf(binder(), ExternalIdUpsertPreprocessor.class);
+
+ // The ChangeExternalIdCaseSensitivity program needs to access all external IDs only
+ // once to update them. After the update they are not accessed again. Hence the
+ // LocalUsernamesToLowerCase program doesn't benefit from caching external IDs and
+ // the external ID cache can be disabled.
+ install(DisabledExternalIdCache.module());
+ }
+ })
+ .injectMembers(this);
+ globalConfig = dbInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
+
+ this.isUserNameCaseInsensitive =
+ globalConfig.getBoolean("auth", "userNameCaseInsensitive", false);
+
+ String message =
+ "auth.userNameCaseInsensitive is set to %b. "
+ + "External IDs will be migrated to be case %ssensitive. Continue?";
+ if (!ui.yesno(
+ true, message, isUserNameCaseInsensitive, isUserNameCaseInsensitive ? "" : "in")) {
+ return 0;
+ }
+
+ Collection<ExternalId> todo = externalIds.all();
+ monitor.beginTask("Converting external ID note names", todo.size());
+
+ manager.start();
+ try {
+ try (Repository repo = repoManager.openRepository(allUsersName)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(repo);
+ for (ExternalId extId : todo) {
+ recomputeExternalIdNoteId(extIdNotes, extId);
+ monitor.update(1);
+ }
+ if (!dryrun) {
+ try (MetaDataUpdate metaDataUpdate =
+ metaDataUpdateServerFactory.get().create(allUsersName)) {
+ metaDataUpdate.setMessage(
+ String.format(
+ "Migration to case %ssensitive usernames",
+ isUserNameCaseInsensitive ? "" : "in"));
+ extIdNotes.commit(metaDataUpdate);
+ }
+ }
+ }
+ } finally {
+ manager.stop();
+ monitor.endTask();
+ }
+
+ int exitCode;
+ if (!dryrun) {
+ updateGerritConfig();
+
+ exitCode = reindexAccounts();
+ } else {
+ exitCode = 0;
+ }
+ return exitCode;
+ }
+
+ private void recomputeExternalIdNoteId(ExternalIdNotes extIdNotes, ExternalId extId)
+ throws DuplicateKeyException, IOException {
+ if (extId.isScheme(SCHEME_GERRIT) || extId.isScheme(SCHEME_USERNAME)) {
+ ExternalIdKeyFactory keyFactory =
+ new ExternalIdKeyFactory(
+ new ExternalIdKeyFactory.Config() {
+ @Override
+ public boolean isUserNameCaseInsensitive() {
+ return !isUserNameCaseInsensitive;
+ }
+ });
+ ExternalId.Key updatedKey = keyFactory.create(extId.key().scheme(), extId.key().id());
+ if (!extId.key().sha1().getName().equals(updatedKey.sha1().getName())) {
+ logger.atInfo().log("Converting note name of external ID: %s", extId.key());
+ ExternalId updatedExtId =
+ externalIdFactory.create(
+ updatedKey, extId.accountId(), extId.email(), extId.password(), extId.blobId());
+ extIdNotes.replace(extId, updatedExtId);
+ }
+ }
+ }
+
+ private void updateGerritConfig() throws IOException, ConfigInvalidException {
+ logger.atInfo().log("Setting auth.userNameCaseInsensitive to true in gerrit.config.");
+ FileBasedConfig config =
+ new FileBasedConfig(
+ globalConfig, getSitePath().resolve("etc/gerrit.config").toFile(), FS.DETECTED);
+ config.load();
+ config.setBoolean("auth", null, "userNameCaseInsensitive", !isUserNameCaseInsensitive);
+ config.save();
+ }
+
+ private int reindexAccounts() throws Exception {
+ monitor.beginTask("Reindex accounts", ProgressMonitor.UNKNOWN);
+ String[] reindexArgs = {
+ "--site-path", getSitePath().toString(), "--index", AccountSchemaDefinitions.NAME
+ };
+ logger.atInfo().log(
+ "Migration complete, reindexing accounts with: reindex %s", String.join(" ", reindexArgs));
+ Reindex reindexPgm = new Reindex();
+ int exitCode = reindexPgm.main(reindexArgs);
+ monitor.endTask();
+ return exitCode;
+ }
+}
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index a3605f7..0a9b4d8 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -181,7 +181,7 @@
private String devCdn = "";
@Option(name = "--dev-cdn", usage = "Use specified cdn for serving static content.")
- private void setDevCdn(String cdn) {
+ void setDevCdn(String cdn) {
if (cdn == null) {
cdn = "";
}
diff --git a/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java b/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
index 8e2f70f..f651994 100644
--- a/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
+++ b/java/com/google/gerrit/pgm/LocalUsernamesToLowerCase.java
@@ -22,6 +22,7 @@
import com.google.gerrit.pgm.util.SiteProgram;
import com.google.gerrit.server.account.externalids.DisabledExternalIdCache;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllUsersName;
@@ -52,6 +53,7 @@
@Inject private AllUsersName allUsersName;
@Inject private Provider<MetaDataUpdate.Server> metaDataUpdateServerFactory;
@Inject private ExternalIdNotes.FactoryNoReindex externalIdNotesFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@Inject private ExternalIds externalIds;
@Override
@@ -105,7 +107,7 @@
String localUserLowerCase = localUser.toLowerCase(Locale.US);
if (!localUser.equals(localUserLowerCase)) {
ExternalId extIdLowerCase =
- ExternalId.create(
+ externalIdFactory.create(
SCHEME_GERRIT,
localUserLowerCase,
extId.accountId(),
diff --git a/java/com/google/gerrit/pgm/init/BaseInit.java b/java/com/google/gerrit/pgm/init/BaseInit.java
index c4b0040..c083296 100644
--- a/java/com/google/gerrit/pgm/init/BaseInit.java
+++ b/java/com/google/gerrit/pgm/init/BaseInit.java
@@ -164,7 +164,6 @@
* Invoked before site init is called.
*
* @param init initializer instance.
- * @throws Exception
*/
protected boolean beforeInit(SiteInit init) throws Exception {
return false;
@@ -174,7 +173,6 @@
* Invoked after site init is called.
*
* @param run completed run instance.
- * @throws Exception
*/
protected void afterInit(SiteRun run) throws Exception {}
diff --git a/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java b/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
index 9519653..e2a1f04 100644
--- a/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
+++ b/java/com/google/gerrit/pgm/init/ExternalIdsOnInit.java
@@ -18,6 +18,7 @@
import com.google.gerrit.pgm.init.api.InitFlags;
import com.google.gerrit.server.GerritPersonIdentProvider;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.SitePaths;
@@ -39,12 +40,18 @@
private final InitFlags flags;
private final SitePaths site;
private final AllUsersName allUsers;
+ private final ExternalIdFactory externalIdFactory;
@Inject
- public ExternalIdsOnInit(InitFlags flags, SitePaths site, AllUsersNameOnInitProvider allUsers) {
+ public ExternalIdsOnInit(
+ InitFlags flags,
+ SitePaths site,
+ AllUsersNameOnInitProvider allUsers,
+ ExternalIdFactory externalIdFactory) {
this.flags = flags;
this.site = site;
this.allUsers = new AllUsersName(allUsers.get());
+ this.externalIdFactory = externalIdFactory;
}
public synchronized void insert(String commitMessage, Collection<ExternalId> extIds)
@@ -52,7 +59,8 @@
File path = getPath();
if (path != null) {
try (Repository allUsersRepo = new FileRepository(path)) {
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, allUsersRepo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, allUsersRepo, externalIdFactory);
extIdNotes.insert(extIds);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, allUsers, allUsersRepo)) {
diff --git a/java/com/google/gerrit/pgm/init/InitAdminUser.java b/java/com/google/gerrit/pgm/init/InitAdminUser.java
index 2e32066..d6a0133 100644
--- a/java/com/google/gerrit/pgm/init/InitAdminUser.java
+++ b/java/com/google/gerrit/pgm/init/InitAdminUser.java
@@ -29,6 +29,7 @@
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.index.account.AccountIndex;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.group.GroupIndex;
@@ -52,6 +53,7 @@
private final ExternalIdsOnInit externalIds;
private final SequencesOnInit sequencesOnInit;
private final GroupsOnInit groupsOnInit;
+ private final ExternalIdFactory externalIdFactory;
private AccountIndexCollection accountIndexCollection;
private GroupIndexCollection groupIndexCollection;
@@ -63,7 +65,8 @@
VersionedAuthorizedKeysOnInit.Factory authorizedKeysFactory,
ExternalIdsOnInit externalIds,
SequencesOnInit sequencesOnInit,
- GroupsOnInit groupsOnInit) {
+ GroupsOnInit groupsOnInit,
+ ExternalIdFactory externalIdFactory) {
this.flags = flags;
this.ui = ui;
this.accounts = accounts;
@@ -71,6 +74,7 @@
this.externalIds = externalIds;
this.sequencesOnInit = sequencesOnInit;
this.groupsOnInit = groupsOnInit;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -107,10 +111,10 @@
String email = readEmail(sshKey);
List<ExternalId> extIds = new ArrayList<>(2);
- extIds.add(ExternalId.createUsername(username, id, httpPassword));
+ extIds.add(externalIdFactory.createUsername(username, id, httpPassword));
if (email != null) {
- extIds.add(ExternalId.createEmail(id, email));
+ extIds.add(externalIdFactory.createEmail(id, email));
}
externalIds.insert("Add external IDs for initial admin user", extIds);
diff --git a/java/com/google/gerrit/pgm/init/InitAuth.java b/java/com/google/gerrit/pgm/init/InitAuth.java
index c15cff3..948ec49 100644
--- a/java/com/google/gerrit/pgm/init/InitAuth.java
+++ b/java/com/google/gerrit/pgm/init/InitAuth.java
@@ -26,6 +26,7 @@
import com.google.gerrit.pgm.init.api.InitFlags;
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.pgm.init.api.Section;
+import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.mail.SignedToken;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -42,11 +43,13 @@
private final Section ldap;
private final Section receive;
private final InitFlags flags;
+ private final SitePaths site;
@Inject
- InitAuth(InitFlags flags, ConsoleUI ui, Section.Factory sections) {
+ InitAuth(InitFlags flags, ConsoleUI ui, final SitePaths site, Section.Factory sections) {
this.flags = flags;
this.ui = ui;
+ this.site = site;
this.auth = sections.get("auth", null);
this.ldap = sections.get("ldap", null);
this.receive = sections.get(RECEIVE, null);
@@ -62,6 +65,10 @@
}
initSignedPush();
+
+ if (site.isNew) {
+ initUserNameCaseSensitivity();
+ }
}
private void initAuthType() {
@@ -156,4 +163,9 @@
boolean enable = ui.yesno(def, "Enable signed push support");
receive.set("enableSignedPush", Boolean.toString(enable));
}
+
+ private void initUserNameCaseSensitivity() {
+ boolean enableCaseInsensitivity = ui.yesno(true, "Use case insensitive usernames");
+ auth.set("userNameCaseInsensitive", Boolean.toString(enableCaseInsensitivity));
+ }
}
diff --git a/java/com/google/gerrit/pgm/init/InitJGitConfig.java b/java/com/google/gerrit/pgm/init/InitJGitConfig.java
index bad55b4..b68e9f7 100644
--- a/java/com/google/gerrit/pgm/init/InitJGitConfig.java
+++ b/java/com/google/gerrit/pgm/init/InitJGitConfig.java
@@ -53,7 +53,8 @@
ConfigConstants.CONFIG_RECEIVE_SECTION, null, ConfigConstants.CONFIG_KEY_AUTOGC, false);
jgitConfig.save();
ui.error(
- "Auto-configured \"receive.autogc = false\" to disable auto-gc after git-receive-pack.");
+ "Auto-configured \"receive.autogc = false\" to disable auto-gc after"
+ + " git-receive-pack.");
} else if (jgitConfig.getBoolean(
ConfigConstants.CONFIG_RECEIVE_SECTION, ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
ui.error(
@@ -72,12 +73,9 @@
ConfigConstants.CONFIG_PROTOCOL_SECTION, null, ConfigConstants.CONFIG_KEY_VERSION);
if (!TransferConfig.ProtocolVersion.V2.version().equals(version)) {
ui.error(
- String.format(
- "HINT: JGit option \"%s.%s = %s\". It's recommended to activate git\n"
- + "wire protocol version 2 to improve git fetch performance.",
- ConfigConstants.CONFIG_PROTOCOL_SECTION,
- ConfigConstants.CONFIG_KEY_VERSION,
- version));
+ "HINT: JGit option \"%s.%s = %s\". It's recommended to activate git\n"
+ + "wire protocol version 2 to improve git fetch performance.",
+ ConfigConstants.CONFIG_PROTOCOL_SECTION, ConfigConstants.CONFIG_KEY_VERSION, version);
}
}
} catch (IOException e) {
diff --git a/java/com/google/gerrit/pgm/init/PluginsDistribution.java b/java/com/google/gerrit/pgm/init/PluginsDistribution.java
index 73720c4..65c96ec 100644
--- a/java/com/google/gerrit/pgm/init/PluginsDistribution.java
+++ b/java/com/google/gerrit/pgm/init/PluginsDistribution.java
@@ -24,6 +24,8 @@
public interface Processor {
/**
+ * Processes the plugin
+ *
* @param pluginName the name of the plugin (without the .jar extension)
* @param in the content of the plugin .jar file. Implementors don't have to close this stream.
* @throws IOException implementations will typically propagate any IOException caused by
diff --git a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
index 5ca239e..abd7d43 100644
--- a/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
+++ b/java/com/google/gerrit/pgm/init/api/AllProjectsConfig.java
@@ -15,15 +15,16 @@
package com.google.gerrit.pgm.init.api;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.project.GroupList;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.inject.Inject;
import java.io.IOException;
+import java.util.Optional;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.Config;
@@ -34,16 +35,18 @@
public class AllProjectsConfig extends VersionedMetaDataOnInit {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- @Nullable private final StoredConfig baseConfig;
+ private final Optional<StoredConfig> baseConfig;
private Config cfg;
private GroupList groupList;
@Inject
- AllProjectsConfig(AllProjectsNameOnInitProvider allProjects, SitePaths site, InitFlags flags) {
+ AllProjectsConfig(
+ AllProjectsNameOnInitProvider allProjects,
+ AllProjectsConfigProvider allProjectsConfigProvider,
+ SitePaths site,
+ InitFlags flags) {
super(flags, site, allProjects.get(), RefNames.REFS_CONFIG);
- this.baseConfig =
- ProjectConfig.Factory.getBaseConfig(
- site, new AllProjectsName(allProjects.get()), Project.nameKey(allProjects.get()));
+ this.baseConfig = allProjectsConfigProvider.get(new AllProjectsName(allProjects.get()));
}
public Config getConfig() {
@@ -62,8 +65,8 @@
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
- if (baseConfig != null) {
- baseConfig.load();
+ if (baseConfig.isPresent()) {
+ baseConfig.get().load();
}
groupList = readGroupList();
cfg = readConfig(ProjectConfig.PROJECT_CONFIG, baseConfig);
diff --git a/java/com/google/gerrit/pgm/init/api/BUILD b/java/com/google/gerrit/pgm/init/api/BUILD
index 693d319..733b9e3 100644
--- a/java/com/google/gerrit/pgm/init/api/BUILD
+++ b/java/com/google/gerrit/pgm/init/api/BUILD
@@ -11,6 +11,7 @@
"//java/com/google/gerrit/server",
"//lib:guava",
"//lib:jgit",
+ "//lib/errorprone:annotations",
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-assistedinject",
diff --git a/java/com/google/gerrit/pgm/init/api/ConsoleUI.java b/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
index ea39a44..dffdde7 100644
--- a/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
+++ b/java/com/google/gerrit/pgm/init/api/ConsoleUI.java
@@ -14,6 +14,8 @@
package com.google.gerrit.pgm.init.api;
+import com.google.errorprone.annotations.FormatMethod;
+import com.google.errorprone.annotations.FormatString;
import com.google.gerrit.common.Die;
import java.io.Console;
import java.util.EnumSet;
@@ -37,7 +39,7 @@
return new Die("aborted by user");
}
- /** @return true if this is a batch UI that has no user interaction. */
+ /** Returns true if this is a batch UI that has no user interaction. */
public abstract boolean isBatch();
/** Display a header message before a series of prompts. */
@@ -75,6 +77,7 @@
public abstract String password(String fmt, Object... args);
/** Display an error message on the system stderr. */
+ @FormatMethod
public void error(String format, Object... args) {
System.err.println(String.format(format, args));
System.err.flush();
@@ -97,6 +100,7 @@
}
@Override
+ @FormatMethod
public boolean yesno(Boolean def, String fmt, Object... args) {
final String prompt = String.format(fmt, args);
for (; ; ) {
@@ -135,7 +139,8 @@
}
@Override
- public String readString(String def, String fmt, Object... args) {
+ @FormatMethod
+ public String readString(String def, @FormatString String fmt, Object... args) {
final String prompt = String.format(fmt, args);
String r;
if (def != null) {
@@ -154,7 +159,9 @@
}
@Override
- public String readString(String def, Set<String> allowedValues, String fmt, Object... args) {
+ @FormatMethod
+ public String readString(
+ String def, Set<String> allowedValues, @FormatString String fmt, Object... args) {
for (; ; ) {
String r = readString(def, fmt, args);
if (allowedValues.contains(r.toLowerCase())) {
@@ -171,6 +178,7 @@
}
@Override
+ @FormatMethod
public String password(String fmt, Object... args) {
final String prompt = String.format(fmt, args);
for (; ; ) {
@@ -195,6 +203,7 @@
}
@Override
+ @FormatMethod
public <T extends Enum<?>, A extends EnumSet<? extends T>> T readEnum(
T def, A options, String fmt, Object... args) {
final String prompt = String.format(fmt, args);
diff --git a/java/com/google/gerrit/pgm/init/api/GitRepositoryManagerOnInit.java b/java/com/google/gerrit/pgm/init/api/GitRepositoryManagerOnInit.java
index a937c4b..8e69eb9 100644
--- a/java/com/google/gerrit/pgm/init/api/GitRepositoryManagerOnInit.java
+++ b/java/com/google/gerrit/pgm/init/api/GitRepositoryManagerOnInit.java
@@ -15,6 +15,7 @@
package com.google.gerrit.pgm.init.api;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
@@ -41,6 +42,18 @@
}
@Override
+ public Status getRepositoryStatus(NameKey name) {
+ try {
+ openRepository(name);
+ } catch (RepositoryNotFoundException e) {
+ return Status.NON_EXISTENT;
+ } catch (IOException e) {
+ return Status.UNAVAILABLE;
+ }
+ return Status.ACTIVE;
+ }
+
+ @Override
public Repository openRepository(Project.NameKey name)
throws RepositoryNotFoundException, IOException {
return new FileRepository(getPath(name));
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index 4db657d..188f30b 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -39,7 +39,7 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
-import com.google.gerrit.server.account.externalids.ExternalIdModule;
+import com.google.gerrit.server.account.externalids.ExternalIdCacheModule;
import com.google.gerrit.server.approval.ApprovalCacheImpl;
import com.google.gerrit.server.cache.CacheRemovalListener;
import com.google.gerrit.server.cache.h2.H2CacheModule;
@@ -79,6 +79,7 @@
import com.google.gerrit.server.project.CommitResource;
import com.google.gerrit.server.project.ProjectCacheImpl;
import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.project.SubmitRequirementsEvaluatorImpl;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.approval.ApprovalModule;
import com.google.gerrit.server.query.change.ChangeData;
@@ -171,7 +172,7 @@
modules.add(new DefaultPermissionBackendModule());
modules.add(new DefaultMemoryCacheModule());
modules.add(new H2CacheModule());
- modules.add(new ExternalIdModule());
+ modules.add(new ExternalIdCacheModule());
modules.add(new GroupModule());
modules.add(new NoteDbModule());
modules.add(AccountCacheImpl.module());
@@ -188,6 +189,7 @@
modules.add(TagCache.module());
modules.add(PureRevertCache.module());
modules.add(new ApprovalModule());
+ modules.add(SubmitRequirementsEvaluatorImpl.module());
factory(CapabilityCollection.Factory.class);
factory(ChangeData.AssistedFactory.class);
factory(ChangeIsVisibleToPredicate.Factory.class);
diff --git a/java/com/google/gerrit/pgm/util/SiteProgram.java b/java/com/google/gerrit/pgm/util/SiteProgram.java
index c3be0a4..c1ba896 100644
--- a/java/com/google/gerrit/pgm/util/SiteProgram.java
+++ b/java/com/google/gerrit/pgm/util/SiteProgram.java
@@ -52,7 +52,7 @@
name = "--site-path",
aliases = {"-d"},
usage = "Local directory containing site data")
- private void setSitePath(String path) {
+ void setSitePath(String path) {
sitePath = Paths.get(path).normalize();
}
@@ -64,7 +64,7 @@
this.sitePath = sitePath.normalize();
}
- /** @return the site path specified on the command line. */
+ /** Returns the site path specified on the command line. */
protected Path getSitePath() {
return sitePath;
}
@@ -76,12 +76,12 @@
}
}
- /** @return provides database connectivity and site path. */
+ /** Provides database connectivity and site path. */
protected Injector createDbInjector() {
return createDbInjector(false);
}
- /** @return provides database connectivity and site path. */
+ /** Provides database connectivity and site path. */
protected Injector createDbInjector(boolean enableMetrics) {
List<Module> modules = new ArrayList<>();
diff --git a/java/com/google/gerrit/server/CancellationMetrics.java b/java/com/google/gerrit/server/CancellationMetrics.java
index 9a1ac9c..f534ccb 100644
--- a/java/com/google/gerrit/server/CancellationMetrics.java
+++ b/java/com/google/gerrit/server/CancellationMetrics.java
@@ -14,12 +14,8 @@
package com.google.gerrit.server;
-import static com.google.common.base.Preconditions.checkState;
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
import com.google.gerrit.common.UsedAt;
+import com.google.gerrit.metrics.Counter1;
import com.google.gerrit.metrics.Counter3;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Field;
@@ -34,6 +30,7 @@
public class CancellationMetrics {
private final Counter3<String, String, String> advisoryDeadlineCount;
private final Counter3<String, String, RequestStateProvider.Reason> cancelledRequestsCount;
+ private final Counter1<String> receiveTimeoutCount;
@Inject
CancellationMetrics(MetricMaker metrics) {
@@ -46,7 +43,7 @@
.build(),
Field.ofString("request_uri", Metadata.Builder::restViewName)
.description(
- "The URI of the request to which the advisory deadline applied"
+ "The redacted URI of the request to which the advisory deadline applied"
+ " (only set for request_type = REST).")
.build(),
Field.ofString("deadline_id", (metadataBuilder, resolveAllUsers) -> {})
@@ -62,7 +59,7 @@
.build(),
Field.ofString("request_uri", Metadata.Builder::restViewName)
.description(
- "The URI of the request that was cancelled"
+ "The redacted URI of the request that was cancelled"
+ " (only set for request_type = REST).")
.build(),
Field.ofEnum(
@@ -71,21 +68,35 @@
Metadata.Builder::cancellationReason)
.description("The reason why the request was cancelled.")
.build());
+
+ this.receiveTimeoutCount =
+ metrics.newCounter(
+ "cancellation/receive_timeout_count",
+ new Description(
+ "Number of requests that are cancelled because receive.timout is exceeded")
+ .setRate(),
+ Field.ofString("cancellation_type", (metadataBuilder, resolveAllUsers) -> {})
+ .description("The cancellation type (graceful or forceful).")
+ .build());
}
public void countAdvisoryDeadline(RequestInfo requestInfo, String deadlineId) {
advisoryDeadlineCount.increment(
- requestInfo.requestType(),
- requestInfo.requestUri().map(CancellationMetrics::redactRequestUri).orElse(""),
- deadlineId);
+ requestInfo.requestType(), requestInfo.redactedRequestUri().orElse(""), deadlineId);
}
public void countCancelledRequest(
RequestInfo requestInfo, RequestStateProvider.Reason cancellationReason) {
cancelledRequestsCount.increment(
- requestInfo.requestType(),
- requestInfo.requestUri().map(CancellationMetrics::redactRequestUri).orElse(""),
- cancellationReason);
+ requestInfo.requestType(), requestInfo.redactedRequestUri().orElse(""), cancellationReason);
+ }
+
+ public void countCancelledRequest(
+ RequestInfo.RequestType requestType,
+ String requestUri,
+ RequestStateProvider.Reason cancellationReason) {
+ cancelledRequestsCount.increment(
+ requestType.name(), RequestInfo.redactRequestUri(requestUri), cancellationReason);
}
@UsedAt(UsedAt.Project.GOOGLE)
@@ -96,56 +107,11 @@
cancelledRequestsCount.increment(requestType, redactedRequestUri, cancellationReason);
}
- /**
- * Redacts resource IDs from the given request URI.
- *
- * <p>resource IDs in the request URI are replaced with '*'.
- *
- * @param requestUri a REST URI that has path segments that alternate between view name and
- * resource IDs (e.g. "/<view>", "/<view>/<id>", "/<view>/<id>/<view>",
- * "/<view>/<id>/<view>/<id>", "/<view>/<id>/<view>/<id>/<view>" etc.), must be given without
- * the '/a' prefix
- * @return the redacted request URI
- */
- @VisibleForTesting
- static String redactRequestUri(String requestUri) {
- requireNonNull(requestUri, "requestUri");
- checkState(!requestUri.startsWith("/a"), "request URI must not start with '/a'");
+ public void countGracefulReceiveTimeout() {
+ receiveTimeoutCount.increment("graceful");
+ }
- StringBuilder redactedRequestUri = new StringBuilder();
-
- boolean hasLeadingSlash = false;
- boolean hasTrailingSlash = false;
- if (requestUri.startsWith("/")) {
- hasLeadingSlash = true;
- requestUri = requestUri.substring(1);
- }
- if (requestUri.endsWith("/")) {
- hasTrailingSlash = true;
- requestUri = requestUri.substring(0, requestUri.length() - 1);
- }
-
- boolean idPathSegment = false;
- for (String pathSegment : Splitter.on('/').split(requestUri)) {
- if (!idPathSegment) {
- redactedRequestUri.append("/" + pathSegment);
- idPathSegment = true;
- } else {
- redactedRequestUri.append("/");
- if (!pathSegment.isEmpty()) {
- redactedRequestUri.append("*");
- }
- idPathSegment = false;
- }
- }
-
- if (!hasLeadingSlash) {
- redactedRequestUri.deleteCharAt(0);
- }
- if (hasTrailingSlash) {
- redactedRequestUri.append('/');
- }
-
- return redactedRequestUri.toString();
+ public void countForcefulReceiveTimeout() {
+ receiveTimeoutCount.increment("forceful");
}
}
diff --git a/java/com/google/gerrit/server/ChangeMessagesUtil.java b/java/com/google/gerrit/server/ChangeMessagesUtil.java
index d8b5d87..8366b09 100644
--- a/java/com/google/gerrit/server/ChangeMessagesUtil.java
+++ b/java/com/google/gerrit/server/ChangeMessagesUtil.java
@@ -127,8 +127,9 @@
}
/**
+ * Determines whether the tag starts with the autogenerated prefix
+ *
* @param tag value of a tag, or null.
- * @return whether the tag starts with the autogenerated prefix.
*/
public static boolean isAutogenerated(@Nullable String tag) {
return tag != null && tag.startsWith(AUTOGENERATED_TAG_PREFIX);
diff --git a/java/com/google/gerrit/server/ChangeUtil.java b/java/com/google/gerrit/server/ChangeUtil.java
index 46e8d33..d9edf42 100644
--- a/java/com/google/gerrit/server/ChangeUtil.java
+++ b/java/com/google/gerrit/server/ChangeUtil.java
@@ -53,7 +53,7 @@
public static final Ordering<PatchSet> PS_ID_ORDER =
Ordering.from(comparingInt(PatchSet::number));
- /** @return a new unique identifier for change message entities. */
+ /** Returns a new unique identifier for change message entities. */
public static String messageUuid() {
byte[] buf = new byte[8];
UUID_RANDOM.nextBytes(buf);
diff --git a/java/com/google/gerrit/server/CurrentUser.java b/java/com/google/gerrit/server/CurrentUser.java
index 7012944..0b5600d 100644
--- a/java/com/google/gerrit/server/CurrentUser.java
+++ b/java/com/google/gerrit/server/CurrentUser.java
@@ -103,7 +103,7 @@
return Optional.empty();
}
- /** @return unique name of the user for logging, never {@code null} */
+ /** Returns unique name of the user for logging, never {@code null} */
public String getLoggableName() {
return getUserName().orElseGet(() -> getClass().getSimpleName());
}
diff --git a/java/com/google/gerrit/server/DeadlineChecker.java b/java/com/google/gerrit/server/DeadlineChecker.java
index 7b231f9..f41b1e3 100644
--- a/java/com/google/gerrit/server/DeadlineChecker.java
+++ b/java/com/google/gerrit/server/DeadlineChecker.java
@@ -14,14 +14,14 @@
package com.google.gerrit.server;
-import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Comparator.comparing;
+import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static java.util.stream.Collectors.toMap;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
@@ -30,33 +30,46 @@
import com.google.gerrit.server.cancellation.RequestStateProvider;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.util.time.TimeUtil;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
+import java.util.HashSet;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
import org.eclipse.jgit.lib.Config;
-/** {@link RequestStateProvider} that checks whether a client provided deadline is exceeded. */
+/**
+ * {@link RequestStateProvider} that checks whether a client provided deadline is exceeded.
+ *
+ * <p>Should be registered at most once per request.
+ */
public class DeadlineChecker implements RequestStateProvider {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static String SECTION_DEADLINE = "deadline";
/**
- * Formatter to format a timeout as {@code timeout=<TIMEOUT><TIME_UNIT>}.
+ * Creates a formatter that formats a timeout as {@code <TIMEOUT_NAME>=<TIMEOUT><TIME_UNIT>}.
*
* <p>If the timeout is 1 minute or greater, minutes is used as a time unit. Otherwise
* milliseconds is just as a time unit.
+ *
+ * @param timeoutName the name of the timeout
*/
- public static Function<Long, String> TIMEOUT_FORMATTER =
- timeout -> {
- String formattedTimeout = MILLISECONDS.convert(timeout, NANOSECONDS) + "ms";
- long timeoutInMinutes = MINUTES.convert(timeout, NANOSECONDS);
- if (timeoutInMinutes > 0) {
- formattedTimeout = timeoutInMinutes + "m";
- }
- return String.format("timeout=%s", formattedTimeout);
- };
+ public static Function<Long, String> getTimeoutFormatter(String timeoutName) {
+ requireNonNull(timeoutName, "timeoutName");
+ return timeout -> {
+ String formattedTimeout = MILLISECONDS.convert(timeout, NANOSECONDS) + "ms";
+ long timeoutInMinutes = MINUTES.convert(timeout, NANOSECONDS);
+ if (timeoutInMinutes > 0) {
+ formattedTimeout = timeoutInMinutes + "m";
+ }
+ return String.format("%s=%s", timeoutName, formattedTimeout);
+ };
+ }
public interface Factory {
DeadlineChecker create(RequestInfo requestInfo, @Nullable String clientProvidedTimeoutValue)
@@ -68,8 +81,13 @@
}
private final CancellationMetrics cancellationsMetrics;
+
+ /** The start time of the request in nanoseconds. */
+ private final long start;
+
private final RequestInfo requestInfo;
private final RequestStateProvider.Reason cancellationReason;
+ private final String timeoutName;
/**
* Timeout in nanoseconds after which the request should be aborted.
@@ -93,10 +111,10 @@
* <p>If any of these deadlines is exceeded the request is not be aborted. Instead the {@code
* cancellation/advisory_deadline_count} metric is incremented and a log is written.
*/
- private final ImmutableList<ServerDeadline> advisoryDeadlines;
+ private final Map<String, ServerDeadline> advisoryDeadlines;
/**
- * Creates a {@code ClientProvidedDeadlineChecker}.
+ * Creates a {@link DeadlineChecker}.
*
* <p>No deadline is enforced if the client provided deadline value is {@code null} or {@code 0}.
*
@@ -117,13 +135,13 @@
this(
serverConfig,
cancellationsMetrics,
- System.nanoTime(),
+ TimeUtil.nowNanos(),
requestInfo,
clientProvidedTimeoutValue);
}
/**
- * Creates a {@code ClientProvidedDeadlineChecker}.
+ * Creates a {@link DeadlineChecker}.
*
* <p>No deadline is enforced if the client provided deadline value is {@code null} or {@code 0}.
*
@@ -144,6 +162,7 @@
@Assisted @Nullable String clientProvidedTimeoutValue)
throws InvalidDeadlineException {
this.cancellationsMetrics = cancellationsMetrics;
+ this.start = start;
this.requestInfo = requestInfo;
ImmutableList<RequestConfig> deadlineConfigs =
@@ -152,6 +171,26 @@
Optional<ServerDeadline> serverSideDeadline =
getServerSideDeadline(deadlineConfigs, requestInfo);
Optional<Long> clientedProvidedTimeout = parseTimeout(clientProvidedTimeoutValue);
+ logDeadlines(serverSideDeadline, clientedProvidedTimeout);
+
+ this.cancellationReason =
+ clientedProvidedTimeout.isPresent()
+ ? RequestStateProvider.Reason.CLIENT_PROVIDED_DEADLINE_EXCEEDED
+ : RequestStateProvider.Reason.SERVER_DEADLINE_EXCEEDED;
+ this.timeoutName =
+ clientedProvidedTimeout
+ .map(clientTimeout -> "client.timeout")
+ .orElse(
+ serverSideDeadline
+ .map(serverDeadline -> serverDeadline.id() + ".timeout")
+ .orElse("timeout"));
+ this.timeout =
+ clientedProvidedTimeout.orElse(serverSideDeadline.map(ServerDeadline::timeout).orElse(0L));
+ this.deadline = timeout > 0 ? Optional.of(start + timeout) : Optional.empty();
+ }
+
+ private void logDeadlines(
+ Optional<ServerDeadline> serverSideDeadline, Optional<Long> clientedProvidedTimeout) {
if (serverSideDeadline.isPresent()) {
if (clientedProvidedTimeout.isPresent()) {
logger.atFine().log(
@@ -167,14 +206,11 @@
TimeUnit.MILLISECONDS.convert(
serverSideDeadline.get().timeout(), TimeUnit.NANOSECONDS));
}
+ } else if (clientedProvidedTimeout.isPresent()) {
+ logger.atFine().log(
+ "applying client provided deadline (timeout = %sms)",
+ TimeUnit.MILLISECONDS.convert(clientedProvidedTimeout.get(), TimeUnit.NANOSECONDS));
}
- this.cancellationReason =
- clientedProvidedTimeout.isPresent()
- ? RequestStateProvider.Reason.CLIENT_PROVIDED_DEADLINE_EXCEEDED
- : RequestStateProvider.Reason.SERVER_DEADLINE_EXCEEDED;
- this.timeout =
- clientedProvidedTimeout.orElse(serverSideDeadline.map(ServerDeadline::timeout).orElse(0L));
- this.deadline = timeout > 0 ? Optional.of(start + timeout) : Optional.empty();
}
private Optional<ServerDeadline> getServerSideDeadline(
@@ -189,32 +225,40 @@
.findFirst();
}
- private ImmutableList<ServerDeadline> getAdvisoryDeadlines(
+ private Map<String, ServerDeadline> getAdvisoryDeadlines(
ImmutableList<RequestConfig> deadlineConfigs, RequestInfo requestInfo) {
return deadlineConfigs.stream()
.filter(deadlineConfig -> deadlineConfig.matches(requestInfo))
.map(ServerDeadline::readFrom)
.filter(ServerDeadline::hasTimeout)
.filter(ServerDeadline::isAdvisory)
- .collect(toImmutableList());
+ .collect(toMap(ServerDeadline::id, Function.identity()));
}
@Override
public void checkIfCancelled(OnCancelled onCancelled) {
- long now = System.nanoTime();
+ long now = TimeUtil.nowNanos();
- advisoryDeadlines.forEach(
- advisoryDeadline -> {
- if (now > advisoryDeadline.timeout()) {
- logger.atWarning().log(
- "advisory deadline %s exceeded (%s)",
- advisoryDeadline.id(), TIMEOUT_FORMATTER.apply(advisoryDeadline.timeout()));
- cancellationsMetrics.countAdvisoryDeadline(requestInfo, advisoryDeadline.id());
- }
- });
+ Set<String> exceededAdvisoryDeadlines = new HashSet<>();
+ advisoryDeadlines
+ .values()
+ .forEach(
+ advisoryDeadline -> {
+ if (now > start + advisoryDeadline.timeout()) {
+ exceededAdvisoryDeadlines.add(advisoryDeadline.id());
+ logger.atFine().log(
+ "advisory deadline exceeded (%s)",
+ getTimeoutFormatter(advisoryDeadline.id() + ".timeout")
+ .apply(advisoryDeadline.timeout()));
+ cancellationsMetrics.countAdvisoryDeadline(requestInfo, advisoryDeadline.id());
+ }
+ });
+ // remove advisory deadlines which have already been reported as exceeded so that they don't get
+ // reported again for this request
+ exceededAdvisoryDeadlines.forEach(advisoryDeadlines::remove);
if (deadline.isPresent() && now > deadline.get()) {
- onCancelled.onCancel(cancellationReason, TIMEOUT_FORMATTER.apply(timeout));
+ onCancelled.onCancel(cancellationReason, getTimeoutFormatter(timeoutName).apply(timeout));
}
}
diff --git a/java/com/google/gerrit/server/IdentifiedUser.java b/java/com/google/gerrit/server/IdentifiedUser.java
index 24ea9d2..eb3e324 100644
--- a/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/java/com/google/gerrit/server/IdentifiedUser.java
@@ -343,15 +343,15 @@
}
/**
- * @return the user's user name; null if one has not been selected/assigned or if the user name is
- * empty.
+ * Returns the user's user name; null if one has not been selected/assigned or if the user name is
+ * empty.
*/
@Override
public Optional<String> getUserName() {
return state().userName();
}
- /** @return unique name of the user for logging, never {@code null} */
+ /** Returns unique name of the user for logging, never {@code null} */
@Override
public String getLoggableName() {
return getUserName()
diff --git a/java/com/google/gerrit/server/PerformanceMetrics.java b/java/com/google/gerrit/server/PerformanceMetrics.java
new file mode 100644
index 0000000..85452ce
--- /dev/null
+++ b/java/com/google/gerrit/server/PerformanceMetrics.java
@@ -0,0 +1,137 @@
+// 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;
+
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.metrics.Counter3;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer3;
+import com.google.gerrit.server.logging.Metadata;
+import com.google.gerrit.server.logging.PerformanceLogger;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.util.concurrent.TimeUnit;
+
+/** Performance logger that records the execution times as a metric. */
+@Singleton
+public class PerformanceMetrics implements PerformanceLogger {
+ private static final String OPERATION_LATENCY_METRIC_NAME = "performance/operations";
+ private static final String OPERATION_COUNT_METRIC_NAME = "performance/operations_count";
+ private static final String PLUGIN_OPERATION_COUNT_METRIC_NAME =
+ "performance/plugin_operations_count";
+
+ public final Timer3<String, String, String> operationsLatency;
+ public final Counter3<String, String, String> operationsCounter;
+ public final Counter3<String, String, String> pluginOperationsCounter;
+
+ @Inject
+ PerformanceMetrics(MetricMaker metricMaker) {
+ Field<String> operationNameField =
+ Field.ofString(
+ "operation_name",
+ (metadataBuilder, fieldValue) -> metadataBuilder.operationName(fieldValue))
+ .description("The operation that was performed.")
+ .build();
+ Field<String> changeIdentifierField =
+ Field.ofString("change_identifier", (metadataBuilder, fieldValue) -> {})
+ .description(
+ "The ID of the change for which the operation was performed"
+ + " (format = '<project>~<numeric-change-id>').")
+ .build();
+ Field<String> traceIdField =
+ Field.ofString("trace_id", (metadataBuilder, fieldValue) -> {})
+ .description("The ID of the trace if tracing was done.")
+ .build();
+ Field<String> requestField =
+ Field.ofString("request", (metadataBuilder, fieldValue) -> {})
+ .description(
+ "The request for which the operation was performed"
+ + " (format = '<request-type> <redacted-request-uri>').")
+ .build();
+ Field<String> pluginField =
+ Field.ofString(
+ "plugin", (metadataBuilder, fieldValue) -> metadataBuilder.pluginName(fieldValue))
+ .description("The name of the plugin that performed the operation.")
+ .build();
+
+ this.operationsLatency =
+ metricMaker.newTimer(
+ OPERATION_LATENCY_METRIC_NAME,
+ new Description("Latency of performing operations")
+ .setCumulative()
+ .setUnit(Description.Units.MILLISECONDS),
+ operationNameField,
+ changeIdentifierField,
+ traceIdField);
+ this.operationsCounter =
+ metricMaker.newCounter(
+ OPERATION_COUNT_METRIC_NAME,
+ new Description("Number of performed operations").setRate(),
+ operationNameField,
+ traceIdField,
+ requestField);
+ this.pluginOperationsCounter =
+ metricMaker.newCounter(
+ PLUGIN_OPERATION_COUNT_METRIC_NAME,
+ new Description("Number of performed operations by plugin").setRate(),
+ operationNameField,
+ pluginField,
+ traceIdField);
+ }
+
+ @Override
+ public void log(String operation, long durationMs) {
+ log(operation, durationMs, /* metadata= */ null);
+ }
+
+ @Override
+ public void log(String operation, long durationMs, @Nullable Metadata metadata) {
+ if (OPERATION_LATENCY_METRIC_NAME.equals(operation)) {
+ // Recording the timer metric below triggers writing a performance log entry. If we are called
+ // for this performance log entry we must abort to avoid an endless loop.
+ // In practice this should not happen since PerformanceLoggers are only called on close() of
+ // the PerformanceLogContext, and hence the performance log that gets written by the metric
+ // below gets ignored.
+ return;
+ }
+
+ String traceId = TraceContext.getTraceId().orElse("");
+
+ operationsLatency.record(
+ operation, formatChangeIdentifier(metadata), traceId, durationMs, TimeUnit.MILLISECONDS);
+
+ String requestTag = TraceContext.getTag(TraceRequestListener.TAG_REQUEST).orElse("");
+ operationsCounter.increment(operation, traceId, requestTag);
+
+ TraceContext.getPluginTag()
+ .ifPresent(pluginName -> pluginOperationsCounter.increment(operation, pluginName, traceId));
+ }
+
+ private String formatChangeIdentifier(@Nullable Metadata metadata) {
+ if (metadata == null
+ || (!metadata.projectName().isPresent() && !metadata.changeId().isPresent())) {
+ return "";
+ }
+
+ StringBuilder sb = new StringBuilder();
+ sb.append(metadata.projectName().orElse("n/a"));
+ sb.append('~');
+ sb.append(metadata.changeId().map(String::valueOf).orElse("n/a"));
+ return sb.toString();
+ }
+}
diff --git a/java/com/google/gerrit/server/RequestConfig.java b/java/com/google/gerrit/server/RequestConfig.java
index 960907d..83cea5b 100644
--- a/java/com/google/gerrit/server/RequestConfig.java
+++ b/java/com/google/gerrit/server/RequestConfig.java
@@ -41,6 +41,7 @@
RequestConfig.Builder requestConfig = RequestConfig.builder(cfg, section, id);
requestConfig.requestTypes(parseRequestTypes(cfg, section, id));
requestConfig.requestUriPatterns(parseRequestUriPatterns(cfg, section, id));
+ requestConfig.excludedRequestUriPatterns(parseExcludedRequestUriPatterns(cfg, section, id));
requestConfig.accountIds(parseAccounts(cfg, section, id));
requestConfig.projectPatterns(parseProjectPatterns(cfg, section, id));
requestConfigs.add(requestConfig.build());
@@ -61,6 +62,11 @@
return parsePatterns(cfg, section, id, "requestUriPattern");
}
+ private static ImmutableSet<Pattern> parseExcludedRequestUriPatterns(
+ Config cfg, String section, String id) throws ConfigInvalidException {
+ return parsePatterns(cfg, section, id, "excludedRequestUriPattern");
+ }
+
private static ImmutableSet<Account.Id> parseAccounts(Config cfg, String section, String id)
throws ConfigInvalidException {
ImmutableSet.Builder<Account.Id> accountIds = ImmutableSet.builder();
@@ -115,6 +121,9 @@
/** pattern matching request URIs */
abstract ImmutableSet<Pattern> requestUriPatterns();
+ /** pattern matching request URIs to be excluded */
+ abstract ImmutableSet<Pattern> excludedRequestUriPatterns();
+
/** accounts IDs matching calling user */
abstract ImmutableSet<Account.Id> accountIds();
@@ -154,6 +163,13 @@
}
}
+ // If the request URI matches an excluded request URI pattern, then the request is not matched.
+ if (requestInfo.requestUri().isPresent()
+ && excludedRequestUriPatterns().stream()
+ .anyMatch(p -> p.matcher(requestInfo.requestUri().get()).matches())) {
+ return false;
+ }
+
// If in the request config accounts are set and none of them matches, then the request is not
// matched.
if (!accountIds().isEmpty()) {
@@ -200,6 +216,8 @@
abstract Builder requestUriPatterns(ImmutableSet<Pattern> requestUriPatterns);
+ abstract Builder excludedRequestUriPatterns(ImmutableSet<Pattern> excludedRequestUriPatterns);
+
abstract Builder accountIds(ImmutableSet<Account.Id> accountIds);
abstract Builder projectPatterns(ImmutableSet<Pattern> projectPatterns);
diff --git a/java/com/google/gerrit/server/RequestInfo.java b/java/com/google/gerrit/server/RequestInfo.java
index f369239..791e228 100644
--- a/java/com/google/gerrit/server/RequestInfo.java
+++ b/java/com/google/gerrit/server/RequestInfo.java
@@ -14,7 +14,13 @@
package com.google.gerrit.server;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
+import com.google.common.base.Splitter;
+import com.google.gerrit.common.UsedAt;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.logging.TraceContext;
import java.util.Optional;
@@ -54,6 +60,16 @@
*/
public abstract Optional<String> requestUri();
+ /**
+ * Redacted request URI.
+ *
+ * <p>Request URI where resource IDs are replaced by '*'.
+ */
+ @Memoized
+ public Optional<String> redactedRequestUri() {
+ return requestUri().map(RequestInfo::redactRequestUri);
+ }
+
/** The user that has sent the request. */
public abstract CurrentUser callingUser();
@@ -67,12 +83,75 @@
*/
public abstract Optional<Project.NameKey> project();
+ @Memoized
+ public String formatForLogging() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(requestType());
+ redactedRequestUri().ifPresent(redactedRequestUri -> sb.append(' ').append(redactedRequestUri));
+ return sb.toString();
+ }
+
+ /**
+ * Redacts resource IDs from the given request URI.
+ *
+ * <p>resource IDs in the request URI are replaced with '*'.
+ *
+ * @param requestUri a REST URI that has path segments that alternate between view name and
+ * resource IDs (e.g. "/<view>", "/<view>/<id>", "/<view>/<id>/<view>",
+ * "/<view>/<id>/<view>/<id>", "/<view>/<id>/<view>/<id>/<view>" etc.), must be given without
+ * the '/a' prefix
+ * @return the redacted request URI
+ */
+ static String redactRequestUri(String requestUri) {
+ requireNonNull(requestUri, "requestUri");
+ checkState(
+ !requestUri.startsWith("/a/"), "request URI must not start with '/a/': %s", requestUri);
+
+ StringBuilder redactedRequestUri = new StringBuilder();
+
+ boolean hasLeadingSlash = false;
+ boolean hasTrailingSlash = false;
+ if (requestUri.startsWith("/")) {
+ hasLeadingSlash = true;
+ requestUri = requestUri.substring(1);
+ }
+ if (requestUri.endsWith("/")) {
+ hasTrailingSlash = true;
+ requestUri = requestUri.substring(0, requestUri.length() - 1);
+ }
+
+ boolean idPathSegment = false;
+ for (String pathSegment : Splitter.on('/').split(requestUri)) {
+ if (!idPathSegment) {
+ redactedRequestUri.append("/" + pathSegment);
+ idPathSegment = true;
+ } else {
+ redactedRequestUri.append("/");
+ if (!pathSegment.isEmpty()) {
+ redactedRequestUri.append("*");
+ }
+ idPathSegment = false;
+ }
+ }
+
+ if (!hasLeadingSlash) {
+ redactedRequestUri.deleteCharAt(0);
+ }
+ if (hasTrailingSlash) {
+ redactedRequestUri.append('/');
+ }
+
+ return redactedRequestUri.toString();
+ }
+
public static RequestInfo.Builder builder(
RequestType requestType, CurrentUser callingUser, TraceContext traceContext) {
- return new AutoValue_RequestInfo.Builder()
- .requestType(requestType)
- .callingUser(callingUser)
- .traceContext(traceContext);
+ return builder().requestType(requestType).callingUser(callingUser).traceContext(traceContext);
+ }
+
+ @UsedAt(UsedAt.Project.GOOGLE)
+ public static RequestInfo.Builder builder() {
+ return new AutoValue_RequestInfo.Builder();
}
@AutoValue.Builder
diff --git a/java/com/google/gerrit/server/StarredChangesUtil.java b/java/com/google/gerrit/server/StarredChangesUtil.java
index 93cf0de..5dcbd01 100644
--- a/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -27,7 +27,6 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.Nullable;
@@ -57,7 +56,6 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -161,8 +159,6 @@
public static final String DEFAULT_LABEL = "star";
public static final String IGNORE_LABEL = "ignore";
- public static final String REVIEWED_LABEL = "reviewed";
- public static final String UNREVIEWED_LABEL = "unreviewed";
public static final ImmutableSortedSet<String> DEFAULT_LABELS =
ImmutableSortedSet.of(DEFAULT_LABEL);
@@ -350,40 +346,6 @@
return isIgnoredBy(rsrc.getChange().getId(), rsrc.getUser().asIdentifiedUser().getAccountId());
}
- private static String getReviewedLabel(Change change) {
- return getReviewedLabel(change.currentPatchSetId().get());
- }
-
- private static String getReviewedLabel(int ps) {
- return REVIEWED_LABEL + "/" + ps;
- }
-
- private static String getUnreviewedLabel(Change change) {
- return getUnreviewedLabel(change.currentPatchSetId().get());
- }
-
- private static String getUnreviewedLabel(int ps) {
- return UNREVIEWED_LABEL + "/" + ps;
- }
-
- public void markAsReviewed(ChangeResource rsrc) throws IllegalLabelException {
- star(
- rsrc.getUser().asIdentifiedUser().getAccountId(),
- rsrc.getProject(),
- rsrc.getChange().getId(),
- ImmutableSet.of(getReviewedLabel(rsrc.getChange())),
- ImmutableSet.of(getUnreviewedLabel(rsrc.getChange())));
- }
-
- public void markAsUnreviewed(ChangeResource rsrc) throws IllegalLabelException {
- star(
- rsrc.getUser().asIdentifiedUser().getAccountId(),
- rsrc.getProject(),
- rsrc.getChange().getId(),
- ImmutableSet.of(getUnreviewedLabel(rsrc.getChange())),
- ImmutableSet.of(getReviewedLabel(rsrc.getChange())));
- }
-
public static StarRef readLabels(Repository repo, String refName) throws IOException {
try (TraceTimer traceTimer =
TraceContext.newTimer(
@@ -422,23 +384,6 @@
if (labels.containsAll(ImmutableSet.of(DEFAULT_LABEL, IGNORE_LABEL))) {
throw new MutuallyExclusiveLabelsException(DEFAULT_LABEL, IGNORE_LABEL);
}
-
- Set<Integer> reviewedPatchSets = getStarredPatchSets(labels, REVIEWED_LABEL);
- Set<Integer> unreviewedPatchSets = getStarredPatchSets(labels, UNREVIEWED_LABEL);
- Optional<Integer> ps =
- Sets.intersection(reviewedPatchSets, unreviewedPatchSets).stream().findFirst();
- if (ps.isPresent()) {
- throw new MutuallyExclusiveLabelsException(
- getReviewedLabel(ps.get()), getUnreviewedLabel(ps.get()));
- }
- }
-
- public static Set<Integer> getStarredPatchSets(Set<String> labels, String label) {
- return labels.stream()
- .filter(l -> l.startsWith(label + "/"))
- .filter(l -> Ints.tryParse(l.substring(label.length() + 1)) != null)
- .map(l -> Integer.valueOf(l.substring(label.length() + 1)))
- .collect(toSet());
}
private static void validateLabels(Collection<String> labels) throws InvalidLabelsException {
diff --git a/java/com/google/gerrit/server/TraceRequestListener.java b/java/com/google/gerrit/server/TraceRequestListener.java
index 7136e47..6cc0982 100644
--- a/java/com/google/gerrit/server/TraceRequestListener.java
+++ b/java/com/google/gerrit/server/TraceRequestListener.java
@@ -28,6 +28,9 @@
*/
@Singleton
public class TraceRequestListener implements RequestListener {
+ public static String TAG_REQUEST = "request";
+
+ private static String TAG_PROJECT = "project";
private static String SECTION_TRACING = "tracing";
private final ImmutableList<RequestConfig> traceConfigs;
@@ -39,7 +42,8 @@
@Override
public void onRequest(RequestInfo requestInfo) {
- requestInfo.project().ifPresent(p -> requestInfo.traceContext().addTag("project", p));
+ requestInfo.traceContext().addTag(TAG_REQUEST, requestInfo.formatForLogging());
+ requestInfo.project().ifPresent(p -> requestInfo.traceContext().addTag(TAG_PROJECT, p));
traceConfigs.stream()
.filter(traceConfig -> traceConfig.matches(requestInfo))
.forEach(
diff --git a/java/com/google/gerrit/server/WebLinks.java b/java/com/google/gerrit/server/WebLinks.java
index 53a7661..3c69573 100644
--- a/java/com/google/gerrit/server/WebLinks.java
+++ b/java/com/google/gerrit/server/WebLinks.java
@@ -92,11 +92,12 @@
}
/**
+ * Returns links for patch sets
+ *
* @param project Project name.
* @param commit SHA1 of commit.
* @param commitMessage the commit message of the commit.
* @param branchName branch of the commit.
- * @return Links for patch sets.
*/
public ImmutableList<WebLinkInfo> getPatchSetLinks(
Project.NameKey project, String commit, String commitMessage, String branchName) {
@@ -106,11 +107,12 @@
}
/**
+ * Returns links for resolving conflicts
+ *
* @param project Project name.
* @param commit SHA1 of commit.
* @param commitMessage the commit message of the commit.
* @param branchName branch of the commit.
- * @return Links for resolving comflicts.
*/
public ImmutableList<WebLinkInfo> getResolveConflictsLinks(
Project.NameKey project, String commit, String commitMessage, String branchName) {
@@ -121,11 +123,12 @@
}
/**
+ * Returns links for patch sets
+ *
* @param project Project name.
* @param revision SHA1 of the parent revision.
* @param commitMessage the commit message of the parent revision.
* @param branchName branch of the revision (and parent revision).
- * @return Links for patch sets.
*/
public ImmutableList<WebLinkInfo> getParentLinks(
Project.NameKey project, String revision, String commitMessage, String branchName) {
@@ -135,10 +138,11 @@
}
/**
+ * Returns links for editing
+ *
* @param project Project name.
* @param revision SHA1 of revision.
* @param file File name.
- * @return Links for editing.
*/
public ImmutableList<WebLinkInfo> getEditLinks(String project, String revision, String file) {
return Patch.isMagic(file)
@@ -147,10 +151,11 @@
}
/**
+ * Returns links for files
+ *
* @param project Project name.
* @param revision SHA1 of revision.
* @param file File name.
- * @return Links for files.
*/
public ImmutableList<WebLinkInfo> getFileLinks(String project, String revision, String file) {
return Patch.isMagic(file)
@@ -159,10 +164,11 @@
}
/**
+ * Returns links for file history
+ *
* @param project Project name.
* @param revision SHA1 of revision.
* @param file File name.
- * @return Links for file history
*/
public ImmutableList<WebLinkInfo> getFileHistoryLinks(
String project, String revision, String file) {
@@ -176,6 +182,8 @@
}
/**
+ * Returns links for file diffs
+ *
* @param project Project name.
* @param patchSetIdA Patch set ID of side A, <code>null</code> if no base patch set was selected.
* @param revisionA SHA1 of revision of side A.
@@ -183,7 +191,6 @@
* @param patchSetIdB Patch set ID of side B.
* @param revisionB SHA1 of revision of side B.
* @param fileB File name of side B.
- * @return Links for file diffs.
*/
public ImmutableList<DiffWebLinkInfo> getDiffLinks(
String project,
@@ -214,26 +221,29 @@
}
/**
+ * Returns links for projects
+ *
* @param project Project name.
- * @return Links for projects.
*/
public ImmutableList<WebLinkInfo> getProjectLinks(String project) {
return filterLinks(projectLinks, webLink -> webLink.getProjectWeblink(project));
}
/**
+ * Returns links for branches
+ *
* @param project Project name
* @param branch Branch name
- * @return Links for branches.
*/
public ImmutableList<WebLinkInfo> getBranchLinks(String project, String branch) {
return filterLinks(branchLinks, webLink -> webLink.getBranchWebLink(project, branch));
}
/**
+ * Returns links for the tag
+ *
* @param project Project name
* @param tag Tag name
- * @return Links for tags.
*/
public ImmutableList<WebLinkInfo> getTagLinks(String project, String tag) {
return filterLinks(tagLinks, webLink -> webLink.getTagWebLink(project, tag));
diff --git a/java/com/google/gerrit/server/account/AccountCacheImpl.java b/java/com/google/gerrit/server/account/AccountCacheImpl.java
index 93e04880..093af68 100644
--- a/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -24,7 +24,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.AllUsersName;
@@ -45,7 +45,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ExecutionException;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
@@ -77,6 +76,7 @@
private final GitRepositoryManager repoManager;
private final AllUsersName allUsersName;
private final DefaultPreferencesCache defaultPreferenceCache;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
AccountCacheImpl(
@@ -85,12 +85,14 @@
LoadingCache<CachedAccountDetails.Key, CachedAccountDetails> accountDetailsCache,
GitRepositoryManager repoManager,
AllUsersName allUsersName,
- DefaultPreferencesCache defaultPreferenceCache) {
+ DefaultPreferencesCache defaultPreferenceCache,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
this.accountDetailsCache = accountDetailsCache;
this.repoManager = repoManager;
this.allUsersName = allUsersName;
this.defaultPreferenceCache = defaultPreferenceCache;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -141,10 +143,10 @@
public Optional<AccountState> getByUsername(String username) {
try {
return externalIds
- .get(ExternalId.Key.create(SCHEME_USERNAME, username))
+ .get(externalIdKeyFactory.create(SCHEME_USERNAME, username))
.map(e -> get(e.accountId()))
.orElseGet(Optional::empty);
- } catch (IOException | ConfigInvalidException e) {
+ } catch (IOException e) {
logger.atWarning().withCause(e).log("Cannot load AccountState for username %s", username);
return Optional.empty();
}
diff --git a/java/com/google/gerrit/server/account/AccountLimits.java b/java/com/google/gerrit/server/account/AccountLimits.java
index 1845f5b..5549d28 100644
--- a/java/com/google/gerrit/server/account/AccountLimits.java
+++ b/java/com/google/gerrit/server/account/AccountLimits.java
@@ -51,7 +51,7 @@
user = currentUser;
}
- /** @return which priority queue the user's tasks should be submitted to. */
+ /** Returns which priority queue the user's tasks should be submitted to. */
public QueueProvider.QueueType getQueueType() {
// If a non-generic group (that is not Anonymous Users or Registered Users)
// grants us INTERACTIVE permission, use the INTERACTIVE queue even if
@@ -99,7 +99,7 @@
return getRange(GlobalCapability.QUERY_LIMIT).getMax();
}
- /** @return true if the user has a permission rule specifying the range. */
+ /** Returns true if the user has a permission rule specifying the range. */
public boolean hasExplicitRange(String permission) {
return GlobalCapability.hasRange(permission) && !getRules(permission).isEmpty();
}
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index 2152e1e..407d2f7 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -36,6 +36,8 @@
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.auth.NoSuchUserException;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -77,6 +79,8 @@
private final GroupsUpdate.Factory groupsUpdateFactory;
private final boolean autoUpdateAccountActiveStatus;
private final SetInactiveFlag setInactiveFlag;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@VisibleForTesting
@Inject
@@ -92,7 +96,9 @@
ProjectCache projectCache,
ExternalIds externalIds,
GroupsUpdate.Factory groupsUpdateFactory,
- SetInactiveFlag setInactiveFlag) {
+ SetInactiveFlag setInactiveFlag,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.sequences = sequences;
this.accounts = accounts;
this.accountsUpdateProvider = accountsUpdateProvider;
@@ -108,13 +114,15 @@
this.autoUpdateAccountActiveStatus =
cfg.getBoolean("auth", "autoUpdateAccountActiveStatus", false);
this.setInactiveFlag = setInactiveFlag;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
- /** @return user identified by this external identity string */
+ /** Returns a user identified by this external identity string */
public Optional<Account.Id> lookup(String externalId) throws AccountException {
try {
- return externalIds.get(ExternalId.Key.parse(externalId)).map(ExternalId::accountId);
- } catch (IOException | ConfigInvalidException e) {
+ return externalIds.get(externalIdKeyFactory.parse(externalId)).map(ExternalId::accountId);
+ } catch (IOException e) {
throw new AccountException("Cannot lookup account " + externalId, e);
}
}
@@ -229,7 +237,7 @@
String oldEmail = extId.email();
if (newEmail != null && !newEmail.equals(oldEmail)) {
ExternalId extIdWithNewEmail =
- ExternalId.create(extId.key(), extId.accountId(), newEmail, extId.password());
+ externalIdFactory.create(extId.key(), extId.accountId(), newEmail, extId.password());
checkEmailNotUsed(extId.accountId(), extIdWithNewEmail);
accountUpdates.add(u -> u.replaceExternalId(extId, extIdWithNewEmail));
@@ -273,7 +281,7 @@
logger.atFine().log("Assigning new Id %s to account", newId);
ExternalId extId =
- ExternalId.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
+ externalIdFactory.createWithEmail(who.getExternalIdKey(), newId, who.getEmailAddress());
logger.atFine().log("Created external Id: %s", extId);
checkEmailNotUsed(newId, extId);
ExternalId userNameExtId =
@@ -348,7 +356,7 @@
"Cannot assign user name \"%s\" to account %s; name does not conform.",
username, accountId));
}
- return ExternalId.create(SCHEME_USERNAME, username, accountId);
+ return externalIdFactory.create(SCHEME_USERNAME, username, accountId);
}
private void checkEmailNotUsed(Account.Id accountId, ExternalId extIdToBeCreated)
@@ -414,7 +422,7 @@
update(who, extId);
} else {
ExternalId newExtId =
- ExternalId.createWithEmail(who.getExternalIdKey(), to, who.getEmailAddress());
+ externalIdFactory.createWithEmail(who.getExternalIdKey(), to, who.getEmailAddress());
checkEmailNotUsed(to, newExtId);
accountsUpdateProvider
.get()
diff --git a/java/com/google/gerrit/server/account/AccountModule.java b/java/com/google/gerrit/server/account/AccountModule.java
new file mode 100644
index 0000000..c1305cf
--- /dev/null
+++ b/java/com/google/gerrit/server/account/AccountModule.java
@@ -0,0 +1,24 @@
+// 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.account;
+
+import com.google.inject.AbstractModule;
+
+public class AccountModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(AuthRequest.Factory.class);
+ }
+}
diff --git a/java/com/google/gerrit/server/account/AccountTagProvider.java b/java/com/google/gerrit/server/account/AccountTagProvider.java
new file mode 100644
index 0000000..ddb1331
--- /dev/null
+++ b/java/com/google/gerrit/server/account/AccountTagProvider.java
@@ -0,0 +1,14 @@
+package com.google.gerrit.server.account;
+
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.extensions.annotations.ExtensionPoint;
+import java.util.List;
+
+/**
+ * An extension point for plugins to define their own account tags in addition to the ones defined
+ * at {@link com.google.gerrit.extensions.common.AccountInfo.Tags}.
+ */
+@ExtensionPoint
+public interface AccountTagProvider {
+ List<String> getTags(Account.Id id);
+}
diff --git a/java/com/google/gerrit/server/account/AuthRequest.java b/java/com/google/gerrit/server/account/AuthRequest.java
index ddb54a6..50ed532 100644
--- a/java/com/google/gerrit/server/account/AuthRequest.java
+++ b/java/com/google/gerrit/server/account/AuthRequest.java
@@ -21,6 +21,9 @@
import com.google.common.base.Strings;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
import java.util.Optional;
/**
@@ -32,31 +35,52 @@
* not all OpenID providers return them, and not all non-OpenID systems can use them.
*/
public class AuthRequest {
- /** Create a request for a local username, such as from LDAP. */
- public static AuthRequest forUser(String username) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_GERRIT, username));
- r.setUserName(username);
- return r;
+ @Singleton
+ public static class Factory {
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public Factory(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
+ public AuthRequest create(ExternalId.Key externalIdKey) {
+ return new AuthRequest(externalIdKey, externalIdKeyFactory);
+ }
+
+ /** Create a request for a local username, such as from LDAP. */
+ public AuthRequest createForUser(String username) {
+ AuthRequest r =
+ new AuthRequest(
+ externalIdKeyFactory.create(SCHEME_GERRIT, username), externalIdKeyFactory);
+ r.setUserName(username);
+ return r;
+ }
+
+ /** Create a request for an external username. */
+ public AuthRequest createForExternalUser(String username) {
+ AuthRequest r =
+ new AuthRequest(
+ externalIdKeyFactory.create(SCHEME_EXTERNAL, username), externalIdKeyFactory);
+ r.setUserName(username);
+ return r;
+ }
+
+ /**
+ * Create a request for an email address registration.
+ *
+ * <p>This type of request should be used only to attach a new email address to an existing user
+ * account.
+ */
+ public AuthRequest createForEmail(String email) {
+ AuthRequest r =
+ new AuthRequest(externalIdKeyFactory.create(SCHEME_MAILTO, email), externalIdKeyFactory);
+ r.setEmailAddress(email);
+ return r;
+ }
}
- /** Create a request for an external username. */
- public static AuthRequest forExternalUser(String username) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_EXTERNAL, username));
- r.setUserName(username);
- return r;
- }
-
- /**
- * Create a request for an email address registration.
- *
- * <p>This type of request should be used only to attach a new email address to an existing user
- * account.
- */
- public static AuthRequest forEmail(String email) {
- AuthRequest r = new AuthRequest(ExternalId.Key.create(SCHEME_MAILTO, email));
- r.setEmailAddress(email);
- return r;
- }
+ private final ExternalIdKeyFactory externalIdKeyFactory;
private ExternalId.Key externalId;
private String password;
@@ -69,8 +93,9 @@
private boolean authProvidesAccountActiveStatus;
private boolean active;
- public AuthRequest(ExternalId.Key externalId) {
+ private AuthRequest(ExternalId.Key externalId, ExternalIdKeyFactory externalIdKeyFactory) {
this.externalId = externalId;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
public ExternalId.Key getExternalIdKey() {
@@ -86,7 +111,7 @@
public void setLocalUser(String localUser) {
if (externalId.isScheme(SCHEME_GERRIT)) {
- externalId = ExternalId.Key.create(SCHEME_GERRIT, localUser);
+ externalId = externalIdKeyFactory.create(SCHEME_GERRIT, localUser);
}
}
diff --git a/java/com/google/gerrit/server/account/GroupBackend.java b/java/com/google/gerrit/server/account/GroupBackend.java
index d6360c5..91edaf2 100644
--- a/java/com/google/gerrit/server/account/GroupBackend.java
+++ b/java/com/google/gerrit/server/account/GroupBackend.java
@@ -26,7 +26,7 @@
/** Implementations of GroupBackend provide lookup and membership accessors to a group system. */
@ExtensionPoint
public interface GroupBackend {
- /** @return {@code true} if the backend can operate on the UUID. */
+ /** Returns {@code true} if the backend can operate on the UUID. */
boolean handles(AccountGroup.UUID uuid);
/**
@@ -38,12 +38,12 @@
@Nullable
GroupDescription.Basic get(AccountGroup.UUID uuid);
- /** @return suggestions for the group name sorted by name. */
+ /** Returns suggestions for the group name sorted by name. */
Collection<GroupReference> suggest(String name, @Nullable ProjectState project);
- /** @return the group membership checker for the backend. */
+ /** Returns the group membership checker for the backend. */
GroupMembership membershipsOf(CurrentUser user);
- /** @return {@code true} if the group with the given UUID is visible to all registered users. */
+ /** Returns {@code true} if the group with the given UUID is visible to all registered users. */
boolean isVisibleToAll(AccountGroup.UUID uuid);
}
diff --git a/java/com/google/gerrit/server/account/GroupCache.java b/java/com/google/gerrit/server/account/GroupCache.java
index d8cac71..1e28d7d 100644
--- a/java/com/google/gerrit/server/account/GroupCache.java
+++ b/java/com/google/gerrit/server/account/GroupCache.java
@@ -103,6 +103,10 @@
*/
void evict(AccountGroup.UUID groupUuid);
- /** @see #evict(AccountGroup.UUID) */
+ /**
+ * Removes the association of the given UUIDs with groups
+ *
+ * <p>See {@link #evict(AccountGroup.UUID)}
+ */
void evict(Collection<AccountGroup.UUID> groupUuid);
}
diff --git a/java/com/google/gerrit/server/account/GroupIncludeCache.java b/java/com/google/gerrit/server/account/GroupIncludeCache.java
index 6547619..d92d9fc 100644
--- a/java/com/google/gerrit/server/account/GroupIncludeCache.java
+++ b/java/com/google/gerrit/server/account/GroupIncludeCache.java
@@ -37,7 +37,7 @@
*/
Collection<AccountGroup.UUID> parentGroupsOf(AccountGroup.UUID groupId);
- /** @return set of any UUIDs that are not internal groups. */
+ /** Returns set of any UUIDs that are not internal groups. */
Collection<AccountGroup.UUID> allExternalMembers();
void evictGroupsWithMember(Account.Id memberId);
diff --git a/java/com/google/gerrit/server/account/InternalAccountDirectory.java b/java/com/google/gerrit/server/account/InternalAccountDirectory.java
index 13b71cf..9d684ac 100644
--- a/java/com/google/gerrit/server/account/InternalAccountDirectory.java
+++ b/java/com/google/gerrit/server/account/InternalAccountDirectory.java
@@ -14,17 +14,19 @@
package com.google.gerrit.server.account;
+import static com.google.common.collect.Streams.stream;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
-import com.google.common.collect.Streams;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.common.AccountInfo.Tags;
import com.google.gerrit.extensions.common.AvatarInfo;
import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
@@ -45,6 +47,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.stream.Stream;
@Singleton
public class InternalAccountDirectory extends AccountDirectory {
@@ -63,6 +66,7 @@
private final Provider<CurrentUser> self;
private final PermissionBackend permissionBackend;
private final ServiceUserClassifier serviceUserClassifier;
+ private final DynamicMap<AccountTagProvider> accountTagProviders;
@Inject
InternalAccountDirectory(
@@ -71,13 +75,15 @@
IdentifiedUser.GenericFactory userFactory,
Provider<CurrentUser> self,
PermissionBackend permissionBackend,
- ServiceUserClassifier serviceUserClassifier) {
+ ServiceUserClassifier serviceUserClassifier,
+ DynamicMap<AccountTagProvider> accountTagProviders) {
this.accountCache = accountCache;
this.avatar = avatar;
this.userFactory = userFactory;
this.self = self;
this.permissionBackend = permissionBackend;
this.serviceUserClassifier = serviceUserClassifier;
+ this.accountTagProviders = accountTagProviders;
}
@Override
@@ -102,7 +108,7 @@
Set<FillOptions> fillOptionsWithoutSecondaryEmails =
Sets.difference(options, EnumSet.of(FillOptions.SECONDARY_EMAILS));
- Set<Account.Id> ids = Streams.stream(in).map(a -> Account.id(a._accountId)).collect(toSet());
+ Set<Account.Id> ids = stream(in).map(a -> Account.id(a._accountId)).collect(toSet());
Map<Account.Id, AccountState> accountStates = accountCache.get(ids);
for (AccountInfo info : in) {
Account.Id id = Account.id(info._accountId);
@@ -160,10 +166,10 @@
}
if (options.contains(FillOptions.TAGS)) {
- info.tags =
- serviceUserClassifier.isServiceUser(account.id())
- ? ImmutableList.of(AccountInfo.Tag.SERVICE_USER)
- : null;
+ List<String> tags = getTags(account.id());
+ if (!tags.isEmpty()) {
+ info.tags = tags;
+ }
}
if (options.contains(FillOptions.AVATARS)) {
@@ -194,6 +200,15 @@
.collect(toList());
}
+ private List<String> getTags(Account.Id id) {
+ Stream<String> tagsFromProviders =
+ stream(accountTagProviders.iterator())
+ .flatMap(accountTagProvider -> accountTagProvider.get().getTags(id).stream());
+ Stream<String> tagsFromServiceUserClassifier =
+ serviceUserClassifier.isServiceUser(id) ? Stream.of(Tags.SERVICE_USER) : Stream.empty();
+ return concat(tagsFromProviders, tagsFromServiceUserClassifier).collect(toList());
+ }
+
private static void addAvatar(
AvatarProvider provider, AccountInfo account, IdentifiedUser user, int size) {
String url = provider.getUrl(user, size);
diff --git a/java/com/google/gerrit/server/account/Realm.java b/java/com/google/gerrit/server/account/Realm.java
index d56ed07..3f642f7 100644
--- a/java/com/google/gerrit/server/account/Realm.java
+++ b/java/com/google/gerrit/server/account/Realm.java
@@ -41,10 +41,10 @@
void onCreateAccount(AuthRequest who, Account account);
- /** @return true if the user has the given email address. */
+ /** Returns true if the user has the given email address. */
boolean hasEmailAddress(IdentifiedUser who, String email);
- /** @return all known email addresses for the identified user. */
+ /** Returns all known email addresses for the identified user. */
Set<String> getEmailAddresses(IdentifiedUser who);
/**
@@ -56,19 +56,13 @@
*/
Account.Id lookup(String accountName) throws IOException;
- /**
- * @return true if the account is active.
- * @throws NamingException
- * @throws LoginException
- * @throws AccountException
- * @throws IOException
- */
+ /** Returns true if the account is active. */
default boolean isActive(@SuppressWarnings("unused") String username)
throws LoginException, NamingException, AccountException, IOException {
return true;
}
- /** @return true if the account is backed by the realm, false otherwise. */
+ /** Returns true if the account is backed by the realm, false otherwise. */
default boolean accountBelongsToRealm(
@SuppressWarnings("unused") Collection<ExternalId> externalIds) {
return false;
diff --git a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
index 27ac9f4..db030f9 100644
--- a/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
+++ b/java/com/google/gerrit/server/account/ServiceUserClassifierImpl.java
@@ -76,7 +76,7 @@
.get(toTraverse.remove(0))
.orElseThrow(() -> new IllegalStateException("invalid subgroup"));
if (seen.contains(currentGroup.getGroupUUID())) {
- logger.atWarning().log(
+ logger.atFine().log(
"Skipping %s because it's a cyclic subgroup", currentGroup.getGroupUUID());
continue;
}
diff --git a/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java b/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
index 30021e6..555a2c1 100644
--- a/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
+++ b/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
@@ -206,7 +206,6 @@
*
* @param pub the public SSH key to be added
* @return the new SSH key
- * @throws InvalidSshKeyException
*/
private AccountSshKey addKey(String pub) throws InvalidSshKeyException {
checkLoaded();
diff --git a/java/com/google/gerrit/server/account/externalids/AllExternalIds.java b/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
index f1fc5cb..e718bcb 100644
--- a/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
+++ b/java/com/google/gerrit/server/account/externalids/AllExternalIds.java
@@ -68,7 +68,8 @@
ExternalIdProto.Builder b =
ExternalIdProto.newBuilder()
.setKey(externalId.key().get())
- .setAccountId(externalId.accountId().get());
+ .setAccountId(externalId.accountId().get())
+ .setIsCaseInsensitive(externalId.isCaseInsensitive());
if (externalId.email() != null) {
b.setEmail(externalId.email());
}
@@ -91,7 +92,7 @@
private static ExternalId toExternalId(ObjectIdConverter idConverter, ExternalIdProto proto) {
return ExternalId.create(
- ExternalId.Key.parse(proto.getKey()),
+ ExternalId.Key.parse(proto.getKey(), proto.getIsCaseInsensitive()),
Account.id(proto.getAccountId()),
// ExternalId treats null and empty strings the same, so no need to distinguish here.
proto.getEmail(),
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalId.java b/java/com/google/gerrit/server/account/externalids/ExternalId.java
index 268812c..30f4094 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalId.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalId.java
@@ -17,35 +17,29 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Objects.requireNonNull;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.flogger.FluentLogger;
import com.google.common.hash.Hashing;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.client.AuthType;
import com.google.gerrit.git.ObjectIds;
-import com.google.gerrit.server.account.HashedPassword;
import java.io.Serializable;
import java.util.Collection;
+import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
-import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
@AutoValue
public abstract class ExternalId implements Serializable {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
// If these regular expressions are modified the same modifications should be done to the
// corresponding regular expressions in the
// com.google.gerrit.client.account.UsernameField class.
@@ -106,10 +100,10 @@
private static final long serialVersionUID = 1L;
- private static final String EXTERNAL_ID_SECTION = "externalId";
- private static final String ACCOUNT_ID_KEY = "accountId";
- private static final String EMAIL_KEY = "email";
- private static final String PASSWORD_KEY = "password";
+ static final String EXTERNAL_ID_SECTION = "externalId";
+ static final String ACCOUNT_ID_KEY = "accountId";
+ static final String EMAIL_KEY = "email";
+ static final String PASSWORD_KEY = "password";
/**
* Scheme used for {@link AuthType#LDAP}, {@link AuthType#CLIENT_SSL_CERT_LDAP}, {@link
@@ -118,6 +112,8 @@
* <p>The name {@code gerrit:} was a very poor choice.
*
* <p>Scheme names must not contain colons (':').
+ *
+ * <p>Will be handled case insensitive, if auth.userNameCaseInsensitive = true.
*/
public static final String SCHEME_GERRIT = "gerrit";
@@ -127,7 +123,11 @@
/** Scheme used to represent only an email address. */
public static final String SCHEME_MAILTO = "mailto";
- /** Scheme for the username used to authenticate an account, e.g. over SSH. */
+ /**
+ * Scheme for the username used to authenticate an account, e.g. over SSH.
+ *
+ * <p>Will be handled case insensitive, if auth.userNameCaseInsensitive = true.
+ */
public static final String SCHEME_USERNAME = "username";
/** Scheme used for GPG public keys. */
@@ -154,10 +154,12 @@
*
* @param scheme the scheme name, must not contain colons (':'), can be {@code null}
* @param id the external ID, must not contain colons (':')
+ * @param isCaseInsensitive whether the external ID key is matched case insensitively
* @return the created external ID key
*/
- public static Key create(@Nullable String scheme, String id) {
- return new AutoValue_ExternalId_Key(Strings.emptyToNull(scheme), id);
+ @VisibleForTesting
+ public static Key create(@Nullable String scheme, String id, boolean isCaseInsensitive) {
+ return new AutoValue_ExternalId_Key(Strings.emptyToNull(scheme), id, isCaseInsensitive);
}
/**
@@ -165,18 +167,21 @@
*
* @return the parsed external ID key
*/
- public static Key parse(String externalId) {
+ @VisibleForTesting
+ public static Key parse(String externalId, boolean isCaseInsensitive) {
int c = externalId.indexOf(':');
if (c < 1 || c >= externalId.length() - 1) {
- return create(null, externalId);
+ return create(null, externalId, isCaseInsensitive);
}
- return create(externalId.substring(0, c), externalId.substring(c + 1));
+ return create(externalId.substring(0, c), externalId.substring(c + 1), isCaseInsensitive);
}
public abstract @Nullable String scheme();
public abstract String id();
+ public abstract boolean isCaseInsensitive();
+
public boolean isScheme(String scheme) {
return scheme.equals(scheme());
}
@@ -186,8 +191,10 @@
* notes branch.
*/
@SuppressWarnings("deprecation") // Use Hashing.sha1 for compatibility.
+ @Memoized
public ObjectId sha1() {
- return ObjectId.fromRaw(Hashing.sha1().hashString(get(), UTF_8).asBytes());
+ String keyString = isCaseInsensitive() ? get().toLowerCase(Locale.US) : get();
+ return ObjectId.fromRaw(Hashing.sha1().hashString(keyString, UTF_8).asBytes());
}
/**
@@ -209,100 +216,27 @@
return get();
}
+ @Override
+ public final boolean equals(Object obj) {
+ if (!(obj instanceof ExternalId.Key)) {
+ return false;
+ }
+ ExternalId.Key o = (ExternalId.Key) obj;
+
+ return sha1().equals(o.sha1());
+ }
+
+ @Override
+ @Memoized
+ public int hashCode() {
+ return Objects.hash(sha1());
+ }
+
public static ImmutableSet<ExternalId.Key> from(Collection<ExternalId> extIds) {
return extIds.stream().map(ExternalId::key).collect(toImmutableSet());
}
}
- /**
- * Creates an external ID.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @return the created external ID
- */
- public static ExternalId create(String scheme, String id, Account.Id accountId) {
- return create(Key.create(scheme, id), accountId, null, null);
- }
-
- /**
- * Creates an external ID.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param email the email of the external ID, may be {@code null}
- * @param hashedPassword the hashed password of the external ID, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId create(
- String scheme,
- String id,
- Account.Id accountId,
- @Nullable String email,
- @Nullable String hashedPassword) {
- return create(Key.create(scheme, id), accountId, email, hashedPassword);
- }
-
- public static ExternalId create(Key key, Account.Id accountId) {
- return create(key, accountId, null, null);
- }
-
- public static ExternalId create(
- Key key, Account.Id accountId, @Nullable String email, @Nullable String hashedPassword) {
- return create(
- key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), null);
- }
-
- public static ExternalId createWithPassword(
- Key key, Account.Id accountId, @Nullable String email, @Nullable String plainPassword) {
- plainPassword = Strings.emptyToNull(plainPassword);
- String hashedPassword =
- plainPassword != null ? HashedPassword.fromPassword(plainPassword).encode() : null;
- return create(key, accountId, email, hashedPassword);
- }
-
- /**
- * Create a external ID for a username (scheme "username").
- *
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param plainPassword the plain HTTP password, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId createUsername(
- String id, Account.Id accountId, @Nullable String plainPassword) {
- return createWithPassword(Key.create(SCHEME_USERNAME, id), accountId, null, plainPassword);
- }
-
- /**
- * Creates an external ID with an email.
- *
- * @param scheme the scheme name, must not contain colons (':')
- * @param id the external ID, must not contain colons (':')
- * @param accountId the ID of the account to which the external ID belongs
- * @param email the email of the external ID, may be {@code null}
- * @return the created external ID
- */
- public static ExternalId createWithEmail(
- String scheme, String id, Account.Id accountId, @Nullable String email) {
- return createWithEmail(Key.create(scheme, id), accountId, email);
- }
-
- public static ExternalId createWithEmail(Key key, Account.Id accountId, @Nullable String email) {
- return create(key, accountId, Strings.emptyToNull(email), null);
- }
-
- public static ExternalId createEmail(Account.Id accountId, String email) {
- return createWithEmail(SCHEME_MAILTO, email, accountId, requireNonNull(email));
- }
-
- static ExternalId create(ExternalId extId, @Nullable ObjectId blobId) {
- return new AutoValue_ExternalId(
- extId.key(), extId.accountId(), extId.email(), extId.password(), blobId);
- }
-
@VisibleForTesting
public static ExternalId create(
Key key,
@@ -311,111 +245,20 @@
@Nullable String hashedPassword,
@Nullable ObjectId blobId) {
return new AutoValue_ExternalId(
- key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), blobId);
- }
-
- /**
- * Parses an external ID from a byte array that contain the external ID as an Git config file
- * text.
- *
- * <p>The Git config must have exactly one externalId subsection with an accountId and optionally
- * email and password:
- *
- * <pre>
- * [externalId "username:jdoe"]
- * accountId = 1003407
- * email = jdoe@example.com
- * password = bcrypt:4:LCbmSBDivK/hhGVQMfkDpA==:XcWn0pKYSVU/UJgOvhidkEtmqCp6oKB7
- * </pre>
- */
- public static ExternalId parse(String noteId, byte[] raw, ObjectId blobId)
- throws ConfigInvalidException {
- requireNonNull(blobId);
-
- Config externalIdConfig = new Config();
- try {
- externalIdConfig.fromText(new String(raw, UTF_8));
- } catch (ConfigInvalidException e) {
- throw invalidConfig(noteId, e.getMessage());
- }
-
- Set<String> externalIdKeys = externalIdConfig.getSubsections(EXTERNAL_ID_SECTION);
- if (externalIdKeys.size() != 1) {
- throw invalidConfig(
- noteId,
- String.format(
- "Expected exactly 1 '%s' section, found %d",
- EXTERNAL_ID_SECTION, externalIdKeys.size()));
- }
-
- String externalIdKeyStr = Iterables.getOnlyElement(externalIdKeys);
- Key externalIdKey = Key.parse(externalIdKeyStr);
- if (externalIdKey == null) {
- throw invalidConfig(noteId, String.format("External ID %s is invalid", externalIdKeyStr));
- }
-
- if (!externalIdKey.sha1().getName().equals(noteId)) {
- throw invalidConfig(
- noteId,
- String.format(
- "SHA1 of external ID '%s' does not match note ID '%s'", externalIdKeyStr, noteId));
- }
-
- String email = externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, EMAIL_KEY);
- String password =
- externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, PASSWORD_KEY);
- int accountId = readAccountId(noteId, externalIdConfig, externalIdKeyStr);
-
- return create(
- externalIdKey,
- Account.id(accountId),
+ key,
+ accountId,
+ key.isCaseInsensitive(),
Strings.emptyToNull(email),
- Strings.emptyToNull(password),
+ Strings.emptyToNull(hashedPassword),
blobId);
}
- private static int readAccountId(String noteId, Config externalIdConfig, String externalIdKeyStr)
- throws ConfigInvalidException {
- String accountIdStr =
- externalIdConfig.getString(EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY);
- if (accountIdStr == null) {
- throw invalidConfig(
- noteId,
- String.format(
- "Value for '%s.%s.%s' is missing, expected account ID",
- EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY));
- }
-
- try {
- int accountId =
- externalIdConfig.getInt(EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY, -1);
- if (accountId < 0) {
- throw invalidConfig(
- noteId,
- String.format(
- "Value %s for '%s.%s.%s' is invalid, expected account ID",
- accountIdStr, EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY));
- }
- return accountId;
- } catch (IllegalArgumentException e) {
- String msg =
- String.format(
- "Value %s for '%s.%s.%s' is invalid, expected account ID",
- accountIdStr, EXTERNAL_ID_SECTION, externalIdKeyStr, ACCOUNT_ID_KEY);
- logger.atSevere().withCause(e).log(msg);
- throw invalidConfig(noteId, msg);
- }
- }
-
- private static ConfigInvalidException invalidConfig(String noteId, String message) {
- return new ConfigInvalidException(
- String.format("Invalid external ID config for note '%s': %s", noteId, message));
- }
-
public abstract Key key();
public abstract Account.Id accountId();
+ public abstract boolean isCaseInsensitive();
+
public abstract @Nullable String email();
public abstract @Nullable String password();
@@ -456,13 +299,15 @@
ExternalId o = (ExternalId) obj;
return Objects.equals(key(), o.key())
&& Objects.equals(accountId(), o.accountId())
+ && Objects.equals(isCaseInsensitive(), o.isCaseInsensitive())
&& Objects.equals(email(), o.email())
&& Objects.equals(password(), o.password());
}
+ @Memoized
@Override
- public final int hashCode() {
- return Objects.hash(key(), accountId(), email(), password());
+ public int hashCode() {
+ return Objects.hash(key(), accountId(), isCaseInsensitive(), email(), password());
}
/**
@@ -479,7 +324,8 @@
* </pre>
*/
@Override
- public final String toString() {
+ @Memoized
+ public String toString() {
Config c = new Config();
writeToConfig(c);
return c.toText();
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
index 902c18b..72d703b 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheLoader.java
@@ -73,6 +73,7 @@
private final Timer0 reloadDifferential;
private final boolean enablePartialReloads;
private final boolean isPersistentCache;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdCacheLoader(
@@ -82,7 +83,8 @@
@Named(ExternalIdCacheImpl.CACHE_NAME)
Provider<Cache<ObjectId, AllExternalIds>> externalIdCache,
MetricMaker metricMaker,
- @GerritServerConfig Config config) {
+ @GerritServerConfig Config config,
+ ExternalIdFactory externalIdFactory) {
this.externalIdReader = externalIdReader;
this.externalIdCache = externalIdCache;
this.gitRepositoryManager = gitRepositoryManager;
@@ -93,7 +95,9 @@
new Description("Total number of external ID cache reloads from Git.")
.setRate()
.setUnit("updates"),
- Field.ofBoolean("partial", Metadata.Builder::partial).build());
+ Field.ofBoolean("partial", Metadata.Builder::partial)
+ .description("Whether the reload was partial.")
+ .build());
this.reloadDifferential =
metricMaker.newTimer(
"notedb/external_id_partial_read_latency",
@@ -105,6 +109,7 @@
config.getBoolean("cache", ExternalIdCacheImpl.CACHE_NAME, "enablePartialReloads", true);
this.isPersistentCache =
config.getInt("cache", ExternalIdCacheImpl.CACHE_NAME, "diskLimit", 0) > 0;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -216,7 +221,7 @@
* @param additions map of name to blob ID for each external ID that should be added
* @param removals set of name {@link ObjectId}s that should be removed
*/
- private static AllExternalIds buildAllExternalIds(
+ private AllExternalIds buildAllExternalIds(
Repository repo,
AllExternalIds oldExternalIds,
Map<ObjectId, ObjectId> additions,
@@ -245,7 +250,7 @@
ExternalId parsedExternalId;
try {
parsedExternalId =
- ExternalId.parse(
+ externalIdFactory.parse(
nameToBlob.getKey().name(),
reader.open(nameToBlob.getValue()).getCachedBytes(),
nameToBlob.getValue());
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java
new file mode 100644
index 0000000..f0ad1b2
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdCacheModule.java
@@ -0,0 +1,47 @@
+// Copyright (C) 2017 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.account.externalids;
+
+import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
+import com.google.inject.TypeLiteral;
+import java.time.Duration;
+import org.eclipse.jgit.lib.ObjectId;
+
+public class ExternalIdCacheModule extends CacheModule {
+ @Override
+ protected void configure() {
+ persist(ExternalIdCacheImpl.CACHE_NAME, ObjectId.class, new TypeLiteral<AllExternalIds>() {})
+ // The cached data is potentially pretty large and we are always only interested
+ // in the latest value. However, due to a race condition, it is possible for different
+ // threads to observe different values of the meta ref, and hence request different keys
+ // from the cache. Extend the cache size by 1 to cover this case, but expire the extra
+ // object after a short period of time, since it may be a potentially large amount of
+ // memory.
+ // When loading a new value because the primary data advanced, we want to leverage the old
+ // cache state to recompute only what changed. This doesn't affect cache size though as
+ // Guava calls the loader first and evicts later on.
+ .maximumWeight(2)
+ .expireFromMemoryAfterAccess(Duration.ofMinutes(1))
+ .loader(ExternalIdCacheLoader.class)
+ .diskLimit(-1)
+ .version(1)
+ .keySerializer(ObjectIdCacheSerializer.INSTANCE)
+ .valueSerializer(AllExternalIds.Serializer.INSTANCE);
+
+ bind(ExternalIdCacheImpl.class);
+ bind(ExternalIdCache.class).to(ExternalIdCacheImpl.class);
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java b/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java
new file mode 100644
index 0000000..ee42d67
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdFactory.java
@@ -0,0 +1,314 @@
+// 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.account.externalids;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.HashedPassword;
+import com.google.gerrit.server.account.externalids.ExternalId.Key;
+import java.util.Set;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ObjectId;
+
+@Singleton
+public class ExternalIdFactory {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public ExternalIdFactory(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @return the created external ID
+ */
+ public ExternalId create(String scheme, String id, Account.Id accountId) {
+ return create(externalIdKeyFactory.create(scheme, id), accountId, null, null);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId create(
+ String scheme,
+ String id,
+ Account.Id accountId,
+ @Nullable String email,
+ @Nullable String hashedPassword) {
+ return create(externalIdKeyFactory.create(scheme, id), accountId, email, hashedPassword);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @return the created external ID
+ */
+ public ExternalId create(Key key, Account.Id accountId) {
+ return create(key, accountId, null, null);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId create(
+ Key key, Account.Id accountId, @Nullable String email, @Nullable String hashedPassword) {
+ return create(
+ key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), null);
+ }
+
+ /**
+ * Creates an external ID adding a hashed password computed from a plain password.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param plainPassword the plain HTTP password, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithPassword(
+ Key key, Account.Id accountId, @Nullable String email, @Nullable String plainPassword) {
+ plainPassword = Strings.emptyToNull(plainPassword);
+ String hashedPassword =
+ plainPassword != null ? HashedPassword.fromPassword(plainPassword).encode() : null;
+ return create(key, accountId, email, hashedPassword);
+ }
+
+ /**
+ * Create a external ID for a username (scheme "username").
+ *
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param plainPassword the plain HTTP password, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createUsername(
+ String id, Account.Id accountId, @Nullable String plainPassword) {
+ return createWithPassword(
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, id),
+ accountId,
+ null,
+ plainPassword);
+ }
+
+ /**
+ * Creates an external ID with an email.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithEmail(
+ String scheme, String id, Account.Id accountId, @Nullable String email) {
+ return createWithEmail(externalIdKeyFactory.create(scheme, id), accountId, email);
+ }
+
+ /**
+ * Creates an external ID with an email.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createWithEmail(Key key, Account.Id accountId, @Nullable String email) {
+ return create(key, accountId, Strings.emptyToNull(email), null);
+ }
+
+ /**
+ * Creates an external ID using the `mailto`-scheme.
+ *
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @return the created external ID
+ */
+ public ExternalId createEmail(Account.Id accountId, String email) {
+ return createWithEmail(ExternalId.SCHEME_MAILTO, email, accountId, requireNonNull(email));
+ }
+
+ ExternalId create(ExternalId extId, @Nullable ObjectId blobId) {
+ return create(extId.key(), extId.accountId(), extId.email(), extId.password(), blobId);
+ }
+
+ /**
+ * Creates an external ID.
+ *
+ * @param key the external Id key
+ * @param accountId the ID of the account to which the external ID belongs
+ * @param email the email of the external ID, may be {@code null}
+ * @param hashedPassword the hashed password of the external ID, may be {@code null}
+ * @param blobId the ID of the note blob in the external IDs branch that stores this external ID.
+ * {@code null} if the external ID was created in code and is not yet stored in Git.
+ * @return the created external ID
+ */
+ public ExternalId create(
+ Key key,
+ Account.Id accountId,
+ @Nullable String email,
+ @Nullable String hashedPassword,
+ @Nullable ObjectId blobId) {
+ return ExternalId.create(
+ key, accountId, Strings.emptyToNull(email), Strings.emptyToNull(hashedPassword), blobId);
+ }
+
+ /**
+ * Parses an external ID from a byte array that contains the external ID as a Git config file
+ * text.
+ *
+ * <p>The Git config must have exactly one externalId subsection with an accountId and optionally
+ * email and password:
+ *
+ * <pre>
+ * [externalId "username:jdoe"]
+ * accountId = 1003407
+ * email = jdoe@example.com
+ * password = bcrypt:4:LCbmSBDivK/hhGVQMfkDpA==:XcWn0pKYSVU/UJgOvhidkEtmqCp6oKB7
+ * </pre>
+ *
+ * @param noteId the SHA-1 sum of the external ID used as the note's ID
+ * @param raw a byte array that contains the external ID as a Git config file text.
+ * @param blobId the ID of the note blob in the external IDs branch that stores this external ID.
+ * {@code null} if the external ID was created in code and is not yet stored in Git.
+ * @return the parsed external ID
+ */
+ public ExternalId parse(String noteId, byte[] raw, ObjectId blobId)
+ throws ConfigInvalidException {
+ requireNonNull(blobId);
+
+ Config externalIdConfig = new Config();
+ try {
+ externalIdConfig.fromText(new String(raw, UTF_8));
+ } catch (ConfigInvalidException e) {
+ throw invalidConfig(noteId, e.getMessage());
+ }
+
+ Set<String> externalIdKeys = externalIdConfig.getSubsections(ExternalId.EXTERNAL_ID_SECTION);
+ if (externalIdKeys.size() != 1) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Expected exactly 1 '%s' section, found %d",
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeys.size()));
+ }
+
+ String externalIdKeyStr = Iterables.getOnlyElement(externalIdKeys);
+ Key externalIdKey = externalIdKeyFactory.parse(externalIdKeyStr);
+ if (externalIdKey == null) {
+ throw invalidConfig(noteId, String.format("External ID %s is invalid", externalIdKeyStr));
+ }
+
+ if (!externalIdKey.sha1().getName().equals(noteId)) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "SHA1 of external ID '%s' does not match note ID '%s'", externalIdKeyStr, noteId));
+ }
+
+ String email =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.EMAIL_KEY);
+ String password =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.PASSWORD_KEY);
+ int accountId = readAccountId(noteId, externalIdConfig, externalIdKeyStr);
+
+ return create(
+ externalIdKey,
+ Account.id(accountId),
+ Strings.emptyToNull(email),
+ Strings.emptyToNull(password),
+ blobId);
+ }
+
+ private static int readAccountId(String noteId, Config externalIdConfig, String externalIdKeyStr)
+ throws ConfigInvalidException {
+ String accountIdStr =
+ externalIdConfig.getString(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY);
+ if (accountIdStr == null) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Value for '%s.%s.%s' is missing, expected account ID",
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY));
+ }
+
+ try {
+ int accountId =
+ externalIdConfig.getInt(
+ ExternalId.EXTERNAL_ID_SECTION, externalIdKeyStr, ExternalId.ACCOUNT_ID_KEY, -1);
+ if (accountId < 0) {
+ throw invalidConfig(
+ noteId,
+ String.format(
+ "Value %s for '%s.%s.%s' is invalid, expected account ID",
+ accountIdStr,
+ ExternalId.EXTERNAL_ID_SECTION,
+ externalIdKeyStr,
+ ExternalId.ACCOUNT_ID_KEY));
+ }
+ return accountId;
+ } catch (IllegalArgumentException e) {
+ String msg =
+ String.format(
+ "Value %s for '%s.%s.%s' is invalid, expected account ID",
+ accountIdStr,
+ ExternalId.EXTERNAL_ID_SECTION,
+ externalIdKeyStr,
+ ExternalId.ACCOUNT_ID_KEY);
+ logger.atSevere().withCause(e).log(msg);
+ throw invalidConfig(noteId, msg);
+ }
+ }
+
+ private static ConfigInvalidException invalidConfig(String noteId, String message) {
+ return new ConfigInvalidException(
+ String.format("Invalid external ID config for note '%s': %s", noteId, message));
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java b/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java
new file mode 100644
index 0000000..95df4a9
--- /dev/null
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdKeyFactory.java
@@ -0,0 +1,89 @@
+// 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.account.externalids;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.server.config.AuthConfig;
+import com.google.inject.ImplementedBy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+@Singleton
+public class ExternalIdKeyFactory {
+ @ImplementedBy(ConfigImpl.class)
+ public interface Config {
+ boolean isUserNameCaseInsensitive();
+ }
+
+ /**
+ * Default implementation {@link Config}
+ *
+ * <p>Internally in google we are using different implementation.
+ */
+ @Singleton
+ public static class ConfigImpl implements Config {
+ private final boolean isUserNameCaseInsensitive;
+
+ @VisibleForTesting
+ @Inject
+ public ConfigImpl(AuthConfig authConfig) {
+ this.isUserNameCaseInsensitive = authConfig.isUserNameCaseInsensitive();
+ }
+
+ @Override
+ public boolean isUserNameCaseInsensitive() {
+ return isUserNameCaseInsensitive;
+ }
+ }
+
+ private final boolean isUserNameCaseInsensitive;
+
+ @Inject
+ public ExternalIdKeyFactory(Config config) {
+ this.isUserNameCaseInsensitive = config.isUserNameCaseInsensitive();
+ }
+
+ /**
+ * Creates an external ID key.
+ *
+ * @param scheme the scheme name, must not contain colons (':'). E.g. {@link
+ * ExternalId#SCHEME_USERNAME}.
+ * @param id the external ID, must not contain colons (':')
+ * @return the created external ID key
+ */
+ public ExternalId.Key create(@Nullable String scheme, String id) {
+ if (scheme != null
+ && (scheme.equals(ExternalId.SCHEME_USERNAME) || scheme.equals(ExternalId.SCHEME_GERRIT))) {
+ return ExternalId.Key.create(scheme, id, isUserNameCaseInsensitive);
+ }
+
+ return ExternalId.Key.create(scheme, id, false);
+ }
+
+ /**
+ * Parses an external ID key from its String representation
+ *
+ * @param externalId String representation of external ID key (e.g. username:johndoe)
+ * @return the external Id key object
+ */
+ public ExternalId.Key parse(String externalId) {
+ int c = externalId.indexOf(':');
+ if (c < 1 || c >= externalId.length() - 1) {
+ return create(null, externalId);
+ }
+ return create(externalId.substring(0, c), externalId.substring(c + 1));
+ }
+}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java b/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
index 3e5d7b8..da7b357 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdModule.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// 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.
@@ -14,34 +14,13 @@
package com.google.gerrit.server.account.externalids;
-import com.google.gerrit.server.cache.CacheModule;
-import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
-import com.google.inject.TypeLiteral;
-import java.time.Duration;
-import org.eclipse.jgit.lib.ObjectId;
+import com.google.inject.AbstractModule;
-public class ExternalIdModule extends CacheModule {
+public class ExternalIdModule extends AbstractModule {
@Override
protected void configure() {
- persist(ExternalIdCacheImpl.CACHE_NAME, ObjectId.class, new TypeLiteral<AllExternalIds>() {})
- // The cached data is potentially pretty large and we are always only interested
- // in the latest value. However, due to a race condition, it is possible for different
- // threads to observe different values of the meta ref, and hence request different keys
- // from the cache. Extend the cache size by 1 to cover this case, but expire the extra
- // object after a short period of time, since it may be a potentially large amount of
- // memory.
- // When loading a new value because the primary data advanced, we want to leverage the old
- // cache state to recompute only what changed. This doesn't affect cache size though as
- // Guava calls the loader first and evicts later on.
- .maximumWeight(2)
- .expireFromMemoryAfterAccess(Duration.ofMinutes(1))
- .loader(ExternalIdCacheLoader.class)
- .diskLimit(-1)
- .version(1)
- .keySerializer(ObjectIdCacheSerializer.INSTANCE)
- .valueSerializer(AllExternalIds.Serializer.INSTANCE);
-
- bind(ExternalIdCacheImpl.class);
- bind(ExternalIdCache.class).to(ExternalIdCacheImpl.class);
+ bind(ExternalIdFactory.class);
+ bind(ExternalIdKeyFactory.class);
+ bind(PasswordVerifier.class);
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
index 435a524..2b9c00a9 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
@@ -99,16 +99,19 @@
protected final MetricMaker metricMaker;
protected final AllUsersName allUsersName;
protected final DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors;
+ protected final ExternalIdFactory externalIdFactory;
protected ExternalIdNotesLoader(
ExternalIdCache externalIdCache,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
this.externalIdCache = externalIdCache;
this.metricMaker = metricMaker;
this.allUsersName = allUsersName;
this.upsertPreprocessors = upsertPreprocessors;
+ this.externalIdFactory = externalIdFactory;
}
/**
@@ -199,22 +202,25 @@
Provider<AccountIndexer> accountIndexer,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
- super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors);
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
+ super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors, externalIdFactory);
this.accountIndexer = accountIndexer;
}
@Override
public ExternalIdNotes load(Repository allUsersRepo)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.load();
}
@Override
public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.load(rev);
}
@@ -232,14 +238,16 @@
ExternalIdCache externalIdCache,
MetricMaker metricMaker,
AllUsersName allUsersName,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
- super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors);
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
+ super(externalIdCache, metricMaker, allUsersName, upsertPreprocessors, externalIdFactory);
}
@Override
public ExternalIdNotes load(Repository allUsersRepo)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.setNoReindex()
.load();
}
@@ -247,7 +255,8 @@
@Override
public ExternalIdNotes load(Repository allUsersRepo, @Nullable ObjectId rev)
throws IOException, ConfigInvalidException {
- return new ExternalIdNotes(metricMaker, allUsersName, allUsersRepo, upsertPreprocessors)
+ return new ExternalIdNotes(
+ metricMaker, allUsersName, allUsersRepo, upsertPreprocessors, externalIdFactory)
.setNoReindex()
.load(rev);
}
@@ -269,10 +278,17 @@
* @return read-only {@link ExternalIdNotes} instance
*/
public static ExternalIdNotes loadReadOnly(
- AllUsersName allUsersName, Repository allUsersRepo, @Nullable ObjectId rev)
+ AllUsersName allUsersName,
+ Repository allUsersRepo,
+ @Nullable ObjectId rev,
+ ExternalIdFactory externalIdFactory)
throws IOException, ConfigInvalidException {
return new ExternalIdNotes(
- new DisabledMetricMaker(), allUsersName, allUsersRepo, DynamicMap.emptyMap())
+ new DisabledMetricMaker(),
+ allUsersName,
+ allUsersRepo,
+ DynamicMap.emptyMap(),
+ externalIdFactory)
.setReadOnly()
.setNoCacheUpdate()
.setNoReindex()
@@ -290,10 +306,14 @@
* @return {@link ExternalIdNotes} instance that doesn't updates caches on save
*/
public static ExternalIdNotes loadNoCacheUpdate(
- AllUsersName allUsersName, Repository allUsersRepo)
+ AllUsersName allUsersName, Repository allUsersRepo, ExternalIdFactory externalIdFactory)
throws IOException, ConfigInvalidException {
return new ExternalIdNotes(
- new DisabledMetricMaker(), allUsersName, allUsersRepo, DynamicMap.emptyMap())
+ new DisabledMetricMaker(),
+ allUsersName,
+ allUsersRepo,
+ DynamicMap.emptyMap(),
+ externalIdFactory)
.setNoCacheUpdate()
.setNoReindex()
.load();
@@ -304,6 +324,7 @@
private final Repository repo;
private final DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors;
private final CallerFinder callerFinder;
+ private final ExternalIdFactory externalIdFactory;
private NoteMap noteMap;
private ObjectId oldRev;
@@ -334,7 +355,8 @@
MetricMaker metricMaker,
AllUsersName allUsersName,
Repository allUsersRepo,
- DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors) {
+ DynamicMap<ExternalIdUpsertPreprocessor> upsertPreprocessors,
+ ExternalIdFactory externalIdFactory) {
this.updateCount =
metricMaker.newCounter(
"notedb/external_id_update_count",
@@ -355,6 +377,7 @@
// 3. direct callers
.addTarget(ExternalIdNotes.class)
.build();
+ this.externalIdFactory = externalIdFactory;
}
public ExternalIdNotes setAfterReadRevision(Runnable afterReadRevision) {
@@ -434,7 +457,7 @@
try (RevWalk rw = new RevWalk(repo)) {
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- return Optional.of(ExternalId.parse(noteId.name(), raw, noteDataId));
+ return Optional.of(externalIdFactory.parse(noteId.name(), raw, noteDataId));
}
}
@@ -468,7 +491,7 @@
for (Note note : noteMap) {
byte[] raw = readNoteData(rw, note.getData());
try {
- b.add(ExternalId.parse(note.getName(), raw, note.getData()));
+ b.add(externalIdFactory.parse(note.getName(), raw, note.getData()));
} catch (ConfigInvalidException | RuntimeException e) {
logger.atSevere().withCause(e).log(
"Ignoring invalid external ID note %s", note.getName());
@@ -840,8 +863,7 @@
*
* <p>If the external ID already exists, it is overwritten.
*/
- private static ExternalId upsert(
- RevWalk rw, ObjectInserter ins, NoteMap noteMap, ExternalId extId)
+ private ExternalId upsert(RevWalk rw, ObjectInserter ins, NoteMap noteMap, ExternalId extId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extId.key().sha1();
Config c = new Config();
@@ -859,7 +881,7 @@
byte[] raw = c.toText().getBytes(UTF_8);
ObjectId noteData = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, noteData);
- return ExternalId.create(extId, noteData);
+ return externalIdFactory.create(extId, noteData);
}
/**
@@ -868,7 +890,7 @@
* @throws IllegalStateException is thrown if there is an existing external ID that has the same
* key, but otherwise doesn't match the specified external ID.
*/
- private static void remove(RevWalk rw, NoteMap noteMap, ExternalId extId)
+ private void remove(RevWalk rw, NoteMap noteMap, ExternalId extId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extId.key().sha1();
if (!noteMap.contains(noteId)) {
@@ -877,7 +899,7 @@
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- ExternalId actualExtId = ExternalId.parse(noteId.name(), raw, noteDataId);
+ ExternalId actualExtId = externalIdFactory.parse(noteId.name(), raw, noteDataId);
checkState(
extId.equals(actualExtId),
"external id %s should be removed, but it doesn't match the actual external id %s",
@@ -894,8 +916,7 @@
* @return the external ID that was removed, {@code null} if no external ID with the specified key
* exists
*/
- @Nullable
- private static ExternalId remove(
+ private ExternalId remove(
RevWalk rw, NoteMap noteMap, ExternalId.Key extIdKey, Account.Id expectedAccountId)
throws IOException, ConfigInvalidException {
ObjectId noteId = extIdKey.sha1();
@@ -905,7 +926,7 @@
ObjectId noteDataId = noteMap.get(noteId);
byte[] raw = readNoteData(rw, noteDataId);
- ExternalId extId = ExternalId.parse(noteId.name(), raw, noteDataId);
+ ExternalId extId = externalIdFactory.parse(noteId.name(), raw, noteDataId);
if (expectedAccountId != null) {
checkState(
expectedAccountId.equals(extId.accountId()),
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java b/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
index f2505fa..0d715ae 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdReader.java
@@ -69,10 +69,14 @@
private boolean failOnLoad = false;
private final Timer0 readAllLatency;
private final Timer0 readSingleLatency;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdReader(
- GitRepositoryManager repoManager, AllUsersName allUsersName, MetricMaker metricMaker) {
+ GitRepositoryManager repoManager,
+ AllUsersName allUsersName,
+ MetricMaker metricMaker,
+ ExternalIdFactory externalIdFactory) {
this.repoManager = repoManager;
this.allUsersName = allUsersName;
this.readAllLatency =
@@ -87,6 +91,7 @@
new Description("Latency for reading a single external ID from NoteDb.")
.setCumulative()
.setUnit(Units.MILLISECONDS));
+ this.externalIdFactory = externalIdFactory;
}
@VisibleForTesting
@@ -106,7 +111,7 @@
try (Timer0.Context ctx = readAllLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, null).all();
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, null, externalIdFactory).all();
}
}
@@ -125,7 +130,7 @@
try (Timer0.Context ctx = readAllLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev).all();
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev, externalIdFactory).all();
}
}
@@ -135,7 +140,7 @@
try (Timer0.Context ctx = readSingleLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, null).get(key);
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, null, externalIdFactory).get(key);
}
}
@@ -146,7 +151,7 @@
try (Timer0.Context ctx = readSingleLatency.start();
Repository repo = repoManager.openRepository(allUsersName)) {
- return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev).get(key);
+ return ExternalIdNotes.loadReadOnly(allUsersName, repo, rev, externalIdFactory).get(key);
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIds.java b/java/com/google/gerrit/server/account/externalids/ExternalIds.java
index 7b0dc57..4e1e524 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIds.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIds.java
@@ -53,7 +53,7 @@
}
/** Returns the specified external ID. */
- public Optional<ExternalId> get(ExternalId.Key key) throws IOException, ConfigInvalidException {
+ public Optional<ExternalId> get(ExternalId.Key key) throws IOException {
return externalIdCache.byKey(key);
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java b/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
index 6a4da09..cf0e5d3 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdsConsistencyChecker.java
@@ -43,29 +43,32 @@
private final AllUsersName allUsers;
private final AccountCache accountCache;
private final OutgoingEmailValidator validator;
+ private final ExternalIdFactory externalIdFactory;
@Inject
ExternalIdsConsistencyChecker(
GitRepositoryManager repoManager,
AllUsersName allUsers,
AccountCache accountCache,
- OutgoingEmailValidator validator) {
+ OutgoingEmailValidator validator,
+ ExternalIdFactory externalIdFactory) {
this.repoManager = repoManager;
this.allUsers = allUsers;
this.accountCache = accountCache;
this.validator = validator;
+ this.externalIdFactory = externalIdFactory;
}
public List<ConsistencyProblemInfo> check() throws IOException, ConfigInvalidException {
try (Repository repo = repoManager.openRepository(allUsers)) {
- return check(ExternalIdNotes.loadReadOnly(allUsers, repo, null));
+ return check(ExternalIdNotes.loadReadOnly(allUsers, repo, null, externalIdFactory));
}
}
public List<ConsistencyProblemInfo> check(ObjectId rev)
throws IOException, ConfigInvalidException {
try (Repository repo = repoManager.openRepository(allUsers)) {
- return check(ExternalIdNotes.loadReadOnly(allUsers, repo, rev));
+ return check(ExternalIdNotes.loadReadOnly(allUsers, repo, rev, externalIdFactory));
}
}
@@ -79,7 +82,7 @@
for (Note note : noteMap) {
byte[] raw = ExternalIdNotes.readNoteData(rw, note.getData());
try {
- ExternalId extId = ExternalId.parse(note.getName(), raw, note.getData());
+ ExternalId extId = externalIdFactory.parse(note.getName(), raw, note.getData());
problems.addAll(validateExternalId(extId));
if (extId.email() != null) {
diff --git a/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java b/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
index 3f2f774..33443c1 100644
--- a/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
+++ b/java/com/google/gerrit/server/account/externalids/PasswordVerifier.java
@@ -20,21 +20,30 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.account.HashedPassword;
+import com.google.inject.Inject;
import java.util.Collection;
/** Checks if a given username and password match a user's external IDs. */
public class PasswordVerifier {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject
+ public PasswordVerifier(ExternalIdKeyFactory externalIdKeyFactory) {
+ this.externalIdKeyFactory = externalIdKeyFactory;
+ }
+
/** Returns {@code true} if there is an external ID matching both the username and password. */
- public static boolean checkPassword(
+ public boolean checkPassword(
Collection<ExternalId> externalIds, String username, @Nullable String password) {
if (password == null) {
return false;
}
for (ExternalId id : externalIds) {
// Only process the "username:$USER" entry, which is unique.
- if (!id.isScheme(SCHEME_USERNAME) || !username.equals(id.key().id())) {
+ if (!id.isScheme(SCHEME_USERNAME)
+ || !id.key().equals(externalIdKeyFactory.create(SCHEME_USERNAME, username))) {
continue;
}
diff --git a/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java b/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
index b8040f7..a42afc3 100644
--- a/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
+++ b/java/com/google/gerrit/server/account/externalids/testing/ExternalIdTestUtil.java
@@ -45,7 +45,9 @@
rw,
ident,
(ins, noteMap) -> {
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), accountId);
+ ExternalId extId =
+ ExternalId.create(
+ ExternalId.Key.parse(externalId, false), accountId, null, null, null);
ObjectId noteId = extId.key().sha1();
Config c = new Config();
extId.writeToConfig(c);
@@ -65,8 +67,10 @@
rw,
ident,
(ins, noteMap) -> {
- ExternalId extId = ExternalId.create(ExternalId.Key.parse(externalId), accountId);
- ObjectId noteId = ExternalId.Key.parse(externalId + "x").sha1();
+ ExternalId extId =
+ ExternalId.create(
+ ExternalId.Key.parse(externalId, false), accountId, null, null, null);
+ ObjectId noteId = ExternalId.Key.parse(externalId + "x", false).sha1();
Config c = new Config();
extId.writeToConfig(c);
byte[] raw = c.toText().getBytes(UTF_8);
@@ -83,7 +87,7 @@
rw,
ident,
(ins, noteMap) -> {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
+ ObjectId noteId = ExternalId.Key.parse(externalId, false).sha1();
byte[] raw = "bad-config".getBytes(UTF_8);
ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, dataBlob);
@@ -98,7 +102,7 @@
rw,
ident,
(ins, noteMap) -> {
- ObjectId noteId = ExternalId.Key.parse(externalId).sha1();
+ ObjectId noteId = ExternalId.Key.parse(externalId, false).sha1();
byte[] raw = "".getBytes(UTF_8);
ObjectId dataBlob = ins.insert(OBJ_BLOB, raw);
noteMap.set(noteId, dataBlob);
diff --git a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
index 1eee10f..b23782f 100644
--- a/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
+++ b/java/com/google/gerrit/server/api/accounts/AccountApiImpl.java
@@ -28,7 +28,6 @@
import com.google.gerrit.extensions.api.accounts.GpgKeyApi;
import com.google.gerrit.extensions.api.accounts.SshKeyInput;
import com.google.gerrit.extensions.api.accounts.StatusInput;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
import com.google.gerrit.extensions.client.EditPreferencesInfo;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
@@ -37,7 +36,6 @@
import com.google.gerrit.extensions.common.AccountExternalIdInfo;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.AgreementInfo;
-import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.EmailInfo;
import com.google.gerrit.extensions.common.GpgKeyInfo;
import com.google.gerrit.extensions.common.GroupInfo;
@@ -86,13 +84,11 @@
import com.google.gerrit.server.restapi.account.SetPreferences;
import com.google.gerrit.server.restapi.account.SshKeys;
import com.google.gerrit.server.restapi.account.StarredChanges;
-import com.google.gerrit.server.restapi.account.Stars;
import com.google.gerrit.server.restapi.change.ChangesCollection;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.List;
import java.util.Map;
-import java.util.SortedSet;
public class AccountApiImpl implements AccountApi {
interface Factory {
@@ -115,9 +111,6 @@
private final DeleteWatchedProjects deleteWatchedProjects;
private final StarredChanges.Create starredChangesCreate;
private final StarredChanges.Delete starredChangesDelete;
- private final Stars stars;
- private final Stars.Get starsGet;
- private final Stars.Post starsPost;
private final GetEmails getEmails;
private final CreateEmail createEmail;
private final DeleteEmail deleteEmail;
@@ -159,9 +152,6 @@
DeleteWatchedProjects deleteWatchedProjects,
StarredChanges.Create starredChangesCreate,
StarredChanges.Delete starredChangesDelete,
- Stars stars,
- Stars.Get starsGet,
- Stars.Post starsPost,
GetEmails getEmails,
CreateEmail createEmail,
DeleteEmail deleteEmail,
@@ -202,9 +192,6 @@
this.deleteWatchedProjects = deleteWatchedProjects;
this.starredChangesCreate = starredChangesCreate;
this.starredChangesDelete = starredChangesDelete;
- this.stars = stars;
- this.starsGet = starsGet;
- this.starsPost = starsPost;
this.getEmails = getEmails;
this.createEmail = createEmail;
this.deleteEmail = deleteEmail;
@@ -384,35 +371,6 @@
}
@Override
- public void setStars(String changeId, StarsInput input) throws RestApiException {
- try {
- AccountResource.Star rsrc = stars.parse(account, IdString.fromUrl(changeId));
- starsPost.apply(rsrc, input);
- } catch (Exception e) {
- throw asRestApiException("Cannot post stars", e);
- }
- }
-
- @Override
- public SortedSet<String> getStars(String changeId) throws RestApiException {
- try {
- AccountResource.Star rsrc = stars.parse(account, IdString.fromUrl(changeId));
- return starsGet.apply(rsrc).value();
- } catch (Exception e) {
- throw asRestApiException("Cannot get stars", e);
- }
- }
-
- @Override
- public List<ChangeInfo> getStarredChanges() throws RestApiException {
- try {
- return stars.list().apply(account).value();
- } catch (Exception e) {
- throw asRestApiException("Cannot get starred changes", e);
- }
- }
-
- @Override
public List<GroupInfo> getGroups() throws RestApiException {
try {
return getGroups.apply(account).value();
diff --git a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
index 6a26f53..cbaf49e 100644
--- a/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
+++ b/java/com/google/gerrit/server/api/changes/ChangeApiImpl.java
@@ -91,8 +91,6 @@
import com.google.gerrit.server.restapi.change.ListChangeDrafts;
import com.google.gerrit.server.restapi.change.ListChangeRobotComments;
import com.google.gerrit.server.restapi.change.ListReviewers;
-import com.google.gerrit.server.restapi.change.MarkAsReviewed;
-import com.google.gerrit.server.restapi.change.MarkAsUnreviewed;
import com.google.gerrit.server.restapi.change.Move;
import com.google.gerrit.server.restapi.change.PostHashtags;
import com.google.gerrit.server.restapi.change.PostPrivate;
@@ -172,8 +170,6 @@
private final DeletePrivate deletePrivate;
private final Ignore ignore;
private final Unignore unignore;
- private final MarkAsReviewed markAsReviewed;
- private final MarkAsUnreviewed markAsUnreviewed;
private final SetWorkInProgress setWip;
private final SetReadyForReview setReady;
private final PutMessage putMessage;
@@ -228,8 +224,6 @@
DeletePrivate deletePrivate,
Ignore ignore,
Unignore unignore,
- MarkAsReviewed markAsReviewed,
- MarkAsUnreviewed markAsUnreviewed,
SetWorkInProgress setWip,
SetReadyForReview setReady,
PutMessage putMessage,
@@ -282,8 +276,6 @@
this.deletePrivate = deletePrivate;
this.ignore = ignore;
this.unignore = unignore;
- this.markAsReviewed = markAsReviewed;
- this.markAsUnreviewed = markAsUnreviewed;
this.setWip = setWip;
this.setReady = setReady;
this.putMessage = putMessage;
@@ -749,22 +741,6 @@
}
@Override
- public void markAsReviewed(boolean reviewed) throws RestApiException {
- // TODO(dborowitz): Convert to RetryingRestModifyView. Needs to plumb BatchUpdate.Factory into
- // StarredChangesUtil.
- try {
- if (reviewed) {
- markAsReviewed.apply(change, new Input());
- } else {
- markAsUnreviewed.apply(change, new Input());
- }
- } catch (StorageException | IllegalLabelException e) {
- throw asRestApiException(
- "Cannot mark change as " + (reviewed ? "reviewed" : "unreviewed"), e);
- }
- }
-
- @Override
public PureRevertInfo pureRevert() throws RestApiException {
return pureRevert(null);
}
diff --git a/java/com/google/gerrit/server/approval/ApprovalCacheImpl.java b/java/com/google/gerrit/server/approval/ApprovalCacheImpl.java
index 93099eb..fd31da9 100644
--- a/java/com/google/gerrit/server/approval/ApprovalCacheImpl.java
+++ b/java/com/google/gerrit/server/approval/ApprovalCacheImpl.java
@@ -36,7 +36,7 @@
import com.google.protobuf.ByteString;
import java.util.concurrent.ExecutionException;
-/** @see ApprovalCache */
+/** Implementation of the {@link ApprovalCache} interface */
public class ApprovalCacheImpl implements ApprovalCache {
private static final String CACHE_NAME = "approvals";
@@ -49,7 +49,7 @@
CACHE_NAME,
Cache.PatchSetApprovalsKeyProto.class,
Cache.AllPatchSetApprovalsProto.class)
- .version(1)
+ .version(2)
.loader(Loader.class)
.keySerializer(new ProtobufSerializer<>(Cache.PatchSetApprovalsKeyProto.parser()))
.valueSerializer(new ProtobufSerializer<>(Cache.AllPatchSetApprovalsProto.parser()));
diff --git a/java/com/google/gerrit/server/approval/ApprovalInference.java b/java/com/google/gerrit/server/approval/ApprovalInference.java
index 8d409e5..4cb080a 100644
--- a/java/com/google/gerrit/server/approval/ApprovalInference.java
+++ b/java/com/google/gerrit/server/approval/ApprovalInference.java
@@ -101,20 +101,29 @@
*/
Iterable<PatchSetApproval> forPatchSet(
ChangeNotes notes, PatchSet.Id psId, @Nullable RevWalk rw, @Nullable Config repoConfig) {
+ PatchSet patchset = notes.getPatchSets().get(psId);
+ if (patchset == null) {
+ return Collections.emptyList();
+ }
+ return forPatchSet(notes, patchset, rw, repoConfig);
+ }
+
+ Iterable<PatchSetApproval> forPatchSet(
+ ChangeNotes notes, PatchSet ps, @Nullable RevWalk rw, @Nullable Config repoConfig) {
ProjectState project;
try (TraceTimer traceTimer =
TraceContext.newTimer(
"Computing labels for patch set",
Metadata.builder()
.changeId(notes.load().getChangeId().get())
- .patchSetId(psId.get())
+ .patchSetId(ps.id().get())
.build())) {
project =
projectCache
.get(notes.getProjectName())
.orElseThrow(illegalState(notes.getProjectName()));
Collection<PatchSetApproval> approvals =
- getForPatchSetWithoutNormalization(notes, project, psId, rw, repoConfig);
+ getForPatchSetWithoutNormalization(notes, project, ps, rw, repoConfig);
return labelNormalizer.normalize(notes, approvals).getNormalized();
}
}
@@ -125,7 +134,8 @@
PatchSet.Id psId,
ChangeKind kind,
LabelType type,
- @Nullable Map<String, FileDiffOutput> modifiedFiles) {
+ @Nullable Map<String, FileDiffOutput> modifiedFiles,
+ @Nullable Map<String, FileDiffOutput> modifiedFilesLastPatchset) {
int n = psa.key().patchSetId().get();
checkArgument(n != psId.get());
@@ -175,7 +185,7 @@
project.getName());
return true;
} else if (type.isCopyAllScoresIfListOfFilesDidNotChange()
- && listOfFilesUnchangedPredicate.match(modifiedFiles)) {
+ && listOfFilesUnchangedPredicate.match(modifiedFiles, modifiedFilesLastPatchset)) {
logger.atFine().log(
"approval %d on label %s of patch set %d of change %d can be copied"
+ " to patch set %d because the label has set "
@@ -310,13 +320,13 @@
private boolean canCopyBasedOnCopyCondition(
ChangeNotes changeNotes,
PatchSetApproval psa,
- PatchSet.Id psId,
+ PatchSet patchSet,
LabelType type,
ChangeKind changeKind) {
if (!type.getCopyCondition().isPresent()) {
return false;
}
- ApprovalContext ctx = ApprovalContext.create(changeNotes, psa, psId, changeKind);
+ ApprovalContext ctx = ApprovalContext.create(changeNotes, psa, patchSet, changeKind);
try {
// Use a request context to run checks as an internal user with expanded visibility. This is
// so that the output of the copy condition does not depend on who is running the current
@@ -335,7 +345,7 @@
private Collection<PatchSetApproval> getForPatchSetWithoutNormalization(
ChangeNotes notes,
ProjectState project,
- PatchSet.Id psId,
+ PatchSet patchSet,
@Nullable RevWalk rw,
@Nullable Config repoConfig) {
checkState(
@@ -344,15 +354,11 @@
project.getNameKey(),
notes.getProjectName());
- PatchSet ps = notes.load().getPatchSets().get(psId);
- if (ps == null) {
- return Collections.emptyList();
- }
-
+ PatchSet.Id psId = patchSet.id();
// Add approvals on the given patch set to the result
Table<String, Account.Id, PatchSetApproval> resultByUser = HashBasedTable.create();
ImmutableList<PatchSetApproval> approvalsForGivenPatchSet =
- notes.load().getApprovals().get(ps.id());
+ notes.load().getApprovals().get(patchSet.id());
approvalsForGivenPatchSet.forEach(psa -> resultByUser.put(psa.label(), psa.accountId(), psa));
// Bail out immediately if this is the first patch set. Return only approvals granted on the
@@ -375,24 +381,29 @@
Iterable<PatchSetApproval> priorApprovals =
getForPatchSetWithoutNormalization(
- notes, project, priorPatchSet.getValue().id(), rw, repoConfig);
+ notes, project, priorPatchSet.getValue(), rw, repoConfig);
if (!priorApprovals.iterator().hasNext()) {
return resultByUser.values();
}
// Add labels from the previous patch set to the result in case the label isn't already there
// and settings as well as change kind allow copying.
- ChangeKind kind =
+ ChangeKind changeKind =
changeKindCache.getChangeKind(
project.getNameKey(),
rw,
repoConfig,
priorPatchSet.getValue().commitId(),
- ps.commitId());
+ patchSet.commitId());
logger.atFine().log(
"change kind for patch set %d of change %d against prior patch set %s is %s",
- ps.id().get(), ps.id().changeId().get(), priorPatchSet.getValue().id().changeId(), kind);
+ patchSet.id().get(),
+ patchSet.id().changeId().get(),
+ priorPatchSet.getValue().id().changeId(),
+ changeKind);
+
Map<String, FileDiffOutput> modifiedFiles = null;
+ Map<String, FileDiffOutput> modifiedFilesLastPatchSet = null;
LabelTypes labelTypes = project.getLabelTypes();
for (PatchSetApproval psa : priorApprovals) {
if (resultByUser.contains(psa.label(), psa.accountId())) {
@@ -403,7 +414,8 @@
if (modifiedFiles == null
&& type.isPresent()
&& type.get().isCopyAllScoresIfListOfFilesDidNotChange()) {
- modifiedFiles = listModifiedFiles(project, ps, priorPatchSet);
+ modifiedFiles = listModifiedFiles(project, patchSet);
+ modifiedFilesLastPatchSet = listModifiedFiles(project, priorPatchSet.getValue());
}
if (!type.isPresent()) {
logger.atFine().log(
@@ -417,11 +429,18 @@
project.getName());
continue;
}
- if (!canCopyBasedOnBooleanLabelConfigs(project, psa, ps.id(), kind, type.get(), modifiedFiles)
- && !canCopyBasedOnCopyCondition(notes, psa, ps.id(), type.get(), kind)) {
+ if (!canCopyBasedOnBooleanLabelConfigs(
+ project,
+ psa,
+ patchSet.id(),
+ changeKind,
+ type.get(),
+ modifiedFiles,
+ modifiedFilesLastPatchSet)
+ && !canCopyBasedOnCopyCondition(notes, psa, patchSet, type.get(), changeKind)) {
continue;
}
- resultByUser.put(psa.label(), psa.accountId(), psa.copyWithPatchSet(ps.id()));
+ resultByUser.put(psa.label(), psa.accountId(), psa.copyWithPatchSet(patchSet.id()));
}
return resultByUser.values();
}
@@ -430,11 +449,14 @@
* Gets the modified files between the two latest patch-sets. Can be used to compute difference in
* files between those two patch-sets .
*/
- private Map<String, FileDiffOutput> listModifiedFiles(
- ProjectState project, PatchSet ps, Map.Entry<PatchSet.Id, PatchSet> priorPatchSet) {
+ private Map<String, FileDiffOutput> listModifiedFiles(ProjectState project, PatchSet ps) {
try {
- return diffOperations.listModifiedFiles(
- project.getNameKey(), priorPatchSet.getValue().commitId(), ps.commitId());
+ Integer parentNum =
+ listOfFilesUnchangedPredicate.isInitialCommit(project.getNameKey(), ps.commitId())
+ ? 0
+ : 1;
+ return diffOperations.listModifiedFilesAgainstParent(
+ project.getNameKey(), ps.commitId(), parentNum);
} catch (DiffNotAvailableException ex) {
throw new StorageException(
"failed to compute difference in files, so won't copy"
diff --git a/java/com/google/gerrit/server/approval/ApprovalsUtil.java b/java/com/google/gerrit/server/approval/ApprovalsUtil.java
index a1cdd99..c2e35d2 100644
--- a/java/com/google/gerrit/server/approval/ApprovalsUtil.java
+++ b/java/com/google/gerrit/server/approval/ApprovalsUtil.java
@@ -278,7 +278,6 @@
* @param ps patch set being approved.
* @param user user adding approvals.
* @param approvals approvals to add.
- * @throws RestApiException
*/
public Iterable<PatchSetApproval> addApprovalsForNewPatchSet(
ChangeUpdate update,
@@ -349,6 +348,10 @@
return approvalInference.forPatchSet(notes, psId, rw, repoConfig);
}
+ public Iterable<PatchSetApproval> byPatchSet(ChangeNotes notes, PatchSet patchSet) {
+ return approvalInference.forPatchSet(notes, patchSet, /* rw= */ null, /* repoConfig= */ null);
+ }
+
public Iterable<PatchSetApproval> byPatchSet(ChangeNotes notes, PatchSet.Id psId) {
return approvalCache.get(notes, psId);
}
diff --git a/java/com/google/gerrit/server/args4j/AccountIdHandler.java b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
index 73a970b..5df4d28 100644
--- a/java/com/google/gerrit/server/args4j/AccountIdHandler.java
+++ b/java/com/google/gerrit/server/args4j/AccountIdHandler.java
@@ -44,12 +44,14 @@
private final AccountResolver accountResolver;
private final AccountManager accountManager;
private final AuthType authType;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
public AccountIdHandler(
AccountResolver accountResolver,
AccountManager accountManager,
AuthConfig authConfig,
+ AuthRequest.Factory authRequestFactory,
@Assisted CmdLineParser parser,
@Assisted OptionDef option,
@Assisted Setter<Account.Id> setter) {
@@ -57,6 +59,7 @@
this.accountResolver = accountResolver;
this.accountManager = accountManager;
this.authType = authConfig.getAuthType();
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -105,7 +108,7 @@
}
try {
- AuthRequest req = AuthRequest.forUser(user);
+ AuthRequest req = authRequestFactory.createForUser(user);
req.setSkipAuthentication(true);
return accountManager.authenticate(req).getAccountId();
} catch (AccountException e) {
diff --git a/java/com/google/gerrit/server/auth/AuthBackend.java b/java/com/google/gerrit/server/auth/AuthBackend.java
index 9ec3366..424ee43 100644
--- a/java/com/google/gerrit/server/auth/AuthBackend.java
+++ b/java/com/google/gerrit/server/auth/AuthBackend.java
@@ -20,7 +20,7 @@
@ExtensionPoint
public interface AuthBackend {
- /** @return an identifier that uniquely describes the backend. */
+ /** Returns an identifier that uniquely describes the backend. */
String getDomain();
/**
diff --git a/java/com/google/gerrit/server/auth/AuthUser.java b/java/com/google/gerrit/server/auth/AuthUser.java
index 987f086..9e1c5ec 100644
--- a/java/com/google/gerrit/server/auth/AuthUser.java
+++ b/java/com/google/gerrit/server/auth/AuthUser.java
@@ -52,18 +52,18 @@
this.username = username;
}
- /** @return the globally unique identifier. */
+ /** Returns the globally unique identifier. */
public final UUID getUUID() {
return uuid;
}
- /** @return the backend specific user name, or null if one does not exist. */
+ /** Returns the backend specific user name, or null if one does not exist. */
@Nullable
public final String getUsername() {
return username;
}
- /** @return {@code true} if {@link #getUsername()} is not null. */
+ /** Returns {@code true} if {@link #getUsername()} is not null. */
public final boolean hasUsername() {
return getUsername() != null;
}
diff --git a/java/com/google/gerrit/server/auth/InternalAuthBackend.java b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
index 2f8886b..ce536f6 100644
--- a/java/com/google/gerrit/server/auth/InternalAuthBackend.java
+++ b/java/com/google/gerrit/server/auth/InternalAuthBackend.java
@@ -26,11 +26,14 @@
public class InternalAuthBackend implements AuthBackend {
private final AccountCache accountCache;
private final AuthConfig authConfig;
+ private final PasswordVerifier passwordVerifier;
@Inject
- InternalAuthBackend(AccountCache accountCache, AuthConfig authConfig) {
+ InternalAuthBackend(
+ AccountCache accountCache, AuthConfig authConfig, PasswordVerifier passwordVerifier) {
this.accountCache = accountCache;
this.authConfig = authConfig;
+ this.passwordVerifier = passwordVerifier;
}
@Override
@@ -63,7 +66,7 @@
+ ": account inactive or not provisioned in Gerrit");
}
- if (!PasswordVerifier.checkPassword(who.externalIds(), username, req.getPassword().get())) {
+ if (!passwordVerifier.checkPassword(who.externalIds(), username, req.getPassword().get())) {
throw new InvalidCredentialsException();
}
return new AuthUser(AuthUser.UUID.create(username), username);
diff --git a/java/com/google/gerrit/server/cache/CacheMetrics.java b/java/com/google/gerrit/server/cache/CacheMetrics.java
index 12194e7..f1fd4a8 100644
--- a/java/com/google/gerrit/server/cache/CacheMetrics.java
+++ b/java/com/google/gerrit/server/cache/CacheMetrics.java
@@ -35,7 +35,9 @@
@Singleton
public class CacheMetrics {
private static final Field<String> F_NAME =
- Field.ofString("cache_name", Metadata.Builder::cacheName).build();
+ Field.ofString("cache_name", Metadata.Builder::cacheName)
+ .description("The name of the cache.")
+ .build();
@Inject
public CacheMetrics(
diff --git a/java/com/google/gerrit/server/cache/ForwardingRemovalListener.java b/java/com/google/gerrit/server/cache/ForwardingRemovalListener.java
index ee672cd..28d57e6 100644
--- a/java/com/google/gerrit/server/cache/ForwardingRemovalListener.java
+++ b/java/com/google/gerrit/server/cache/ForwardingRemovalListener.java
@@ -25,9 +25,6 @@
/**
* This listener dispatches removal events to all other RemovalListeners attached via the DynamicSet
* API.
- *
- * @param <K>
- * @param <V>
*/
@SuppressWarnings("rawtypes")
public class ForwardingRemovalListener<K, V> implements RemovalListener<K, V> {
diff --git a/java/com/google/gerrit/server/change/ChangeFinder.java b/java/com/google/gerrit/server/change/ChangeFinder.java
index ba104d8..9f253de 100644
--- a/java/com/google/gerrit/server/change/ChangeFinder.java
+++ b/java/com/google/gerrit/server/change/ChangeFinder.java
@@ -96,6 +96,7 @@
.setRate()
.setUnit("requests"),
Field.ofEnum(ChangeIdType.class, "change_id_type", Metadata.Builder::changeIdType)
+ .description("The type of the change identifier.")
.build());
}
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 89069e2..db25dc7 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -79,6 +79,7 @@
import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.extensions.common.ReviewerUpdateInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.extensions.common.SubmitRecordInfo;
import com.google.gerrit.extensions.common.SubmitRequirementExpressionInfo;
import com.google.gerrit.extensions.common.SubmitRequirementResultInfo;
import com.google.gerrit.extensions.common.TrackingIdInfo;
@@ -98,6 +99,7 @@
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.account.AccountInfoComparator;
import com.google.gerrit.server.account.AccountLoader;
+import com.google.gerrit.server.cancellation.RequestCancelledException;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.TrackingFooters;
import com.google.gerrit.server.index.change.ChangeField;
@@ -368,6 +370,14 @@
return reqInfos;
}
+ private Collection<SubmitRecordInfo> submitRecordsFor(ChangeData cd) {
+ List<SubmitRecordInfo> submitRecordInfos = new ArrayList<>();
+ for (SubmitRecord record : cd.submitRecords(SUBMIT_RULE_OPTIONS_STRICT)) {
+ submitRecordInfos.add(submitRecordToInfo(record));
+ }
+ return submitRecordInfos;
+ }
+
private static Collection<SubmitRequirementResultInfo> submitRequirementsFor(ChangeData cd) {
Collection<SubmitRequirementResultInfo> reqInfos = new ArrayList<>();
Map<SubmitRequirement, SubmitRequirementResult> requirements = cd.submitRequirements();
@@ -382,6 +392,34 @@
return new LegacySubmitRequirementInfo(status.name(), req.fallbackText(), req.type());
}
+ private SubmitRecordInfo submitRecordToInfo(SubmitRecord record) {
+ SubmitRecordInfo info = new SubmitRecordInfo();
+ if (record.status != null) {
+ info.status = SubmitRecordInfo.Status.valueOf(record.status.name());
+ }
+ info.ruleName = record.ruleName;
+ info.errorMessage = record.errorMessage;
+ if (record.labels != null) {
+ info.labels = new ArrayList<>();
+ for (SubmitRecord.Label label : record.labels) {
+ SubmitRecordInfo.Label labelInfo = new SubmitRecordInfo.Label();
+ labelInfo.label = label.label;
+ if (label.status != null) {
+ labelInfo.status = SubmitRecordInfo.Label.Status.valueOf(label.status.name());
+ }
+ labelInfo.appliedBy = accountLoader.get(label.appliedBy);
+ info.labels.add(labelInfo);
+ }
+ }
+ if (record.requirements != null) {
+ info.requirements = new ArrayList<>();
+ for (LegacySubmitRequirement requirement : record.requirements) {
+ info.requirements.add(requirementToInfo(requirement, record.status));
+ }
+ }
+ return info;
+ }
+
private static SubmitRequirementResultInfo submitRequirementToInfo(
SubmitRequirement req, SubmitRequirementResult result) {
SubmitRequirementResultInfo info = new SubmitRequirementResultInfo();
@@ -401,6 +439,7 @@
submitRequirementExpressionToInfo(
req.submittabilityExpression(), result.submittabilityExpressionResult());
info.status = SubmitRequirementResultInfo.Status.valueOf(result.status().toString());
+ info.isLegacy = result.legacy();
return info;
}
@@ -509,6 +548,11 @@
cache.put(Change.id(info._number), info);
}
} catch (RuntimeException e) {
+ Optional<RequestCancelledException> requestCancelledException =
+ RequestCancelledException.getFromCausalChain(e);
+ if (requestCancelledException.isPresent()) {
+ throw e;
+ }
logger.atWarning().withCause(e).log(
"Omitting corrupt change %s from results", cd.getId());
}
@@ -655,6 +699,7 @@
out.labels = labelsJson.labelsFor(accountLoader, cd, has(LABELS), has(DETAILED_LABELS));
out.requirements = requirementsFor(cd);
+ out.submitRecords = submitRecordsFor(cd);
if (has(SUBMIT_REQUIREMENTS)) {
out.submitRequirements = submitRequirementsFor(cd);
}
diff --git a/java/com/google/gerrit/server/change/ChangeResource.java b/java/com/google/gerrit/server/change/ChangeResource.java
index 0d0df0d..970f1b5 100644
--- a/java/com/google/gerrit/server/change/ChangeResource.java
+++ b/java/com/google/gerrit/server/change/ChangeResource.java
@@ -140,7 +140,7 @@
return changeData.getId();
}
- /** @return true if {@link #getUser()} is the change's owner. */
+ /** Returns true if {@link #getUser()} is the change's owner. */
public boolean isUserOwner() {
Account.Id owner = getChange().getOwner();
return user.isIdentifiedUser() && user.asIdentifiedUser().getAccountId().equals(owner);
diff --git a/java/com/google/gerrit/server/change/EmailReviewComments.java b/java/com/google/gerrit/server/change/EmailReviewComments.java
index d433c4e..3c7ea44 100644
--- a/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -45,6 +45,8 @@
// TODO(dborowitz/wyatta): Rationalize these arguments so HTML and text templates are operating
// on the same set of inputs.
/**
+ * Creates handle for sending email
+ *
* @param notify setting for handling notification.
* @param notes change notes.
* @param patchSet patch set corresponding to the top-level op
@@ -57,7 +59,6 @@
* contents should *not* include a "Patch set N" header or "(M comments)" footer, as these
* will be added automatically in soy in a structured way.
* @param labels labels applied as part of this review operation.
- * @return handle for sending email.
*/
EmailReviewComments create(
NotifyResolver.Result notify,
diff --git a/java/com/google/gerrit/server/change/FileContentUtil.java b/java/com/google/gerrit/server/change/FileContentUtil.java
index 49c1fe2..c54b902 100644
--- a/java/com/google/gerrit/server/change/FileContentUtil.java
+++ b/java/com/google/gerrit/server/change/FileContentUtil.java
@@ -76,8 +76,6 @@
* @param parent A 1-based parent index to get the content from instead. Null if the content
* should be obtained from {@code revstr} instead.
* @return Content of the file as {@code BinaryResult}.
- * @throws ResourceNotFoundException
- * @throws IOException
*/
public BinaryResult getContent(
ProjectState project, ObjectId revstr, String path, @Nullable Integer parent)
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java
deleted file mode 100644
index a926147..0000000
--- a/java/com/google/gerrit/server/change/FileInfoJsonComparingImpl.java
+++ /dev/null
@@ -1,167 +0,0 @@
-// 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.change;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
-import com.google.gerrit.entities.Project;
-import com.google.gerrit.extensions.common.FileInfo;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.metrics.Counter1;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.Field;
-import com.google.gerrit.metrics.MetricMaker;
-import com.google.gerrit.server.logging.Metadata;
-import com.google.gerrit.server.patch.DiffExecutor;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import org.eclipse.jgit.lib.ObjectId;
-
-/**
- * Implementation of FileInfoJson which uses {@link FileInfoJsonOldImpl}, but also runs {@link
- * FileInfoJsonNewImpl} asynchronously and compares the results. This implementation is temporary
- * and will be used to verify that the results are the same.
- */
-public class FileInfoJsonComparingImpl implements FileInfoJson {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final FileInfoJsonOldImpl oldImpl;
- private final FileInfoJsonNewImpl newImpl;
- private final ExecutorService executor;
- private final Metrics metrics;
-
- /**
- * TODO(ghareeb): These metrics are temporary for launching the new diff cache redesign and are
- * not documented. These will be removed soon.
- */
- @VisibleForTesting
- @Singleton
- static class Metrics {
- private enum Status {
- MATCH,
- MISMATCH,
- ERROR
- }
-
- final Counter1<Status> diffs;
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- diffs =
- metricMaker.newCounter(
- "diff/list_files/dark_launch",
- new Description(
- "Total number of matching, non-matching, or error in list-files diffs in the old and new diff cache implementations.")
- .setRate()
- .setUnit("count"),
- Field.ofEnum(Status.class, "type", Metadata.Builder::eventType).build());
- }
- }
-
- @Inject
- public FileInfoJsonComparingImpl(
- FileInfoJsonOldImpl oldImpl,
- FileInfoJsonNewImpl newImpl,
- @DiffExecutor ExecutorService executor,
- Metrics metrics) {
- this.oldImpl = oldImpl;
- this.newImpl = newImpl;
- this.executor = executor;
- this.metrics = metrics;
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Change change, ObjectId objectId, @Nullable PatchSet base)
- throws ResourceConflictException, PatchListNotAvailableException {
- Map<String, FileInfo> result = oldImpl.getFileInfoMap(change, objectId, base);
- @SuppressWarnings("unused")
- Future<?> ignored =
- executor.submit(
- () -> {
- try {
- Map<String, FileInfo> fileInfoNew = newImpl.getFileInfoMap(change, objectId, base);
- compareAndLogMetrics(
- result,
- fileInfoNew,
- String.format(
- "Mismatch comparing old and new diff implementations for change: %s, objectId: %s and base: %s",
- change, objectId, base == null ? "none" : base.id()));
- } catch (ResourceConflictException | PatchListNotAvailableException e) {
- // If an exception happens while evaluating the new diff, increment the non-matching
- // counter
- metrics.diffs.increment(Metrics.Status.ERROR);
- logger.atWarning().withCause(e).log(
- "Error comparing old and new diff implementations.");
- }
- });
- return result;
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Project.NameKey project, ObjectId objectId, int parentNum)
- throws ResourceConflictException, PatchListNotAvailableException {
- Map<String, FileInfo> result = oldImpl.getFileInfoMap(project, objectId, parentNum);
- @SuppressWarnings("unused")
- Future<?> ignored =
- executor.submit(
- () -> {
- try {
- Map<String, FileInfo> resultNew =
- newImpl.getFileInfoMap(project, objectId, parentNum);
- compareAndLogMetrics(
- result,
- resultNew,
- String.format(
- "Mismatch comparing old and new diff implementations for project: %s, objectId: %s and parentNum: %d",
- project, objectId, parentNum));
- } catch (ResourceConflictException | PatchListNotAvailableException e) {
- // If an exception happens while evaluating the new diff, increment the non-matching
- // ctr
- metrics.diffs.increment(Metrics.Status.ERROR);
- logger.atWarning().withCause(e).log(
- "Error comparing old and new diff implementations.");
- }
- });
- return result;
- }
-
- private void compareAndLogMetrics(
- Map<String, FileInfo> fileInfoMapOld,
- Map<String, FileInfo> fileInfoMapNew,
- String warningMessage) {
- if (fileInfoMapOld.equals(fileInfoMapNew)) {
- metrics.diffs.increment(Metrics.Status.MATCH);
- return;
- }
- metrics.diffs.increment(Metrics.Status.MISMATCH);
- logger.atWarning().log(
- warningMessage
- + "\n"
- + "Result using old impl: "
- + fileInfoMapOld
- + "\n"
- + "Result using new impl: "
- + fileInfoMapNew);
- }
-}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonExperimentImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonExperimentImpl.java
deleted file mode 100644
index 81f014d..0000000
--- a/java/com/google/gerrit/server/change/FileInfoJsonExperimentImpl.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.change;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
-import com.google.gerrit.entities.Project;
-import com.google.gerrit.extensions.common.FileInfo;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.server.experiments.ExperimentFeatures;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import java.util.Map;
-import javax.inject.Inject;
-import org.eclipse.jgit.lib.ObjectId;
-
-/**
- * An experimental implementation of FileInfoJson that uses {@link FileInfoJsonNewImpl} if the
- * experiment flag "GerritBackendRequestFeature__use_new_diff_cache" is enabled, or {@link
- * FileInfoJsonOldImpl} otherwise. This would enable a gradual rollout of {@link
- * FileInfoJsonNewImpl}.
- */
-public class FileInfoJsonExperimentImpl implements FileInfoJson {
- @VisibleForTesting
- public static final String NEW_DIFF_CACHE_FEATURE =
- "GerritBackendRequestFeature__use_new_diff_cache";
-
- private final FileInfoJsonOldImpl oldImpl;
- private final FileInfoJsonNewImpl newImpl;
- private final ExperimentFeatures experimentFeatures;
-
- @Inject
- public FileInfoJsonExperimentImpl(
- FileInfoJsonOldImpl oldImpl,
- FileInfoJsonNewImpl newImpl,
- ExperimentFeatures experimentFeatures) {
- this.oldImpl = oldImpl;
- this.newImpl = newImpl;
- this.experimentFeatures = experimentFeatures;
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Change change, ObjectId objectId, @Nullable PatchSet base)
- throws ResourceConflictException, PatchListNotAvailableException {
- return experimentFeatures.isFeatureEnabled(NEW_DIFF_CACHE_FEATURE)
- ? newImpl.getFileInfoMap(change, objectId, base)
- : oldImpl.getFileInfoMap(change, objectId, base);
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Project.NameKey project, ObjectId objectId, int parentNum)
- throws ResourceConflictException, PatchListNotAvailableException {
- return experimentFeatures.isFeatureEnabled(NEW_DIFF_CACHE_FEATURE)
- ? newImpl.getFileInfoMap(project, objectId, parentNum)
- : oldImpl.getFileInfoMap(project, objectId, parentNum);
- }
-}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonImpl.java
similarity index 95%
rename from java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
rename to java/com/google/gerrit/server/change/FileInfoJsonImpl.java
index 7277404..b729c11 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonNewImpl.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonImpl.java
@@ -32,12 +32,12 @@
import org.eclipse.jgit.errors.NoMergeBaseException;
import org.eclipse.jgit.lib.ObjectId;
-/** Implementation of {@link FileInfoJson} using the new diff cache {@link DiffOperations}. */
-public class FileInfoJsonNewImpl implements FileInfoJson {
+/** Implementation of {@link FileInfoJson} using {@link DiffOperations}. */
+public class FileInfoJsonImpl implements FileInfoJson {
private final DiffOperations diffs;
@Inject
- FileInfoJsonNewImpl(DiffOperations diffOperations) {
+ FileInfoJsonImpl(DiffOperations diffOperations) {
this.diffs = diffOperations;
}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonModule.java b/java/com/google/gerrit/server/change/FileInfoJsonModule.java
index 952b503..b8e05f0 100644
--- a/java/com/google/gerrit/server/change/FileInfoJsonModule.java
+++ b/java/com/google/gerrit/server/change/FileInfoJsonModule.java
@@ -20,7 +20,6 @@
@Override
public void configure() {
- // Binding to the experimental implementation to enable gradual rollout of the new diff cache.
- bind(FileInfoJson.class).to(FileInfoJsonExperimentImpl.class);
+ bind(FileInfoJson.class).to(FileInfoJsonImpl.class);
}
}
diff --git a/java/com/google/gerrit/server/change/FileInfoJsonOldImpl.java b/java/com/google/gerrit/server/change/FileInfoJsonOldImpl.java
deleted file mode 100644
index 0570296..0000000
--- a/java/com/google/gerrit/server/change/FileInfoJsonOldImpl.java
+++ /dev/null
@@ -1,128 +0,0 @@
-// 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.change;
-
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.Patch;
-import com.google.gerrit.entities.PatchSet;
-import com.google.gerrit.entities.Project;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
-import com.google.gerrit.extensions.common.FileInfo;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.concurrent.ExecutionException;
-import org.eclipse.jgit.errors.NoMergeBaseException;
-import org.eclipse.jgit.lib.ObjectId;
-
-/** Implementation of {@link FileInfoJson} using the old diff cache {@link PatchListCache}. */
-@Deprecated
-@Singleton
-class FileInfoJsonOldImpl implements FileInfoJson {
- private final PatchListCache patchListCache;
-
- @Inject
- FileInfoJsonOldImpl(PatchListCache patchListCache) {
- this.patchListCache = patchListCache;
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Change change, ObjectId objectId, @Nullable PatchSet base)
- throws ResourceConflictException, PatchListNotAvailableException {
- ObjectId a = base != null ? base.commitId() : null;
- return toFileInfoMap(change, PatchListKey.againstCommit(a, objectId, Whitespace.IGNORE_NONE));
- }
-
- @Override
- public Map<String, FileInfo> getFileInfoMap(
- Project.NameKey project, ObjectId objectId, int parentNum)
- throws ResourceConflictException, PatchListNotAvailableException {
- PatchListKey key =
- parentNum == 0
- ? PatchListKey.againstDefaultBase(objectId, Whitespace.IGNORE_NONE)
- : PatchListKey.againstParentNum(
- parentNum, objectId, DiffPreferencesInfo.Whitespace.IGNORE_NONE);
- return toFileInfoMap(project, key);
- }
-
- private Map<String, FileInfo> toFileInfoMap(Change change, PatchListKey key)
- throws ResourceConflictException, PatchListNotAvailableException {
- return toFileInfoMap(change.getProject(), key);
- }
-
- Map<String, FileInfo> toFileInfoMap(Project.NameKey project, PatchListKey key)
- throws ResourceConflictException, PatchListNotAvailableException {
- PatchList list;
- try {
- list = patchListCache.get(key, project);
- } catch (PatchListNotAvailableException e) {
- Throwable cause = e.getCause();
- if (cause instanceof ExecutionException) {
- cause = cause.getCause();
- }
- if (cause instanceof NoMergeBaseException) {
- throw new ResourceConflictException(
- String.format("Cannot create auto merge commit: %s", e.getMessage()), e);
- }
- throw e;
- }
-
- Map<String, FileInfo> files = new TreeMap<>();
- for (PatchListEntry e : list.getPatches()) {
- FileInfo fileInfo = new FileInfo();
- fileInfo.status =
- e.getChangeType() != Patch.ChangeType.MODIFIED ? e.getChangeType().getCode() : null;
- fileInfo.oldPath = e.getOldName();
- fileInfo.sizeDelta = e.getSizeDelta();
- fileInfo.size = e.getSize();
- if (e.getPatchType() == Patch.PatchType.BINARY) {
- fileInfo.binary = true;
- } else {
- fileInfo.linesInserted = e.getInsertions() > 0 ? e.getInsertions() : null;
- fileInfo.linesDeleted = e.getDeletions() > 0 ? e.getDeletions() : null;
- }
-
- FileInfo o = files.put(e.getNewName(), fileInfo);
- if (o != null) {
- // This should only happen on a delete-add break created by JGit
- // when the file was rewritten and too little content survived. Write
- // a single record with data from both sides.
- fileInfo.status = Patch.ChangeType.REWRITE.getCode();
- fileInfo.sizeDelta = o.sizeDelta;
- fileInfo.size = o.size;
- if (o.binary != null && o.binary) {
- fileInfo.binary = true;
- }
- if (o.linesInserted != null) {
- fileInfo.linesInserted = o.linesInserted;
- }
- if (o.linesDeleted != null) {
- fileInfo.linesDeleted = o.linesDeleted;
- }
- }
- }
- return files;
- }
-}
diff --git a/java/com/google/gerrit/server/change/IncludedIn.java b/java/com/google/gerrit/server/change/IncludedIn.java
index 3c66c2c..c06ce82 100644
--- a/java/com/google/gerrit/server/change/IncludedIn.java
+++ b/java/com/google/gerrit/server/change/IncludedIn.java
@@ -14,6 +14,12 @@
package com.google.gerrit.server.change;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
+import static java.util.Comparator.naturalOrder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.entities.Project;
@@ -23,13 +29,18 @@
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
+import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Collection;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
@@ -37,17 +48,21 @@
@Singleton
public class IncludedIn {
private final GitRepositoryManager repoManager;
+ private final PermissionBackend permissionBackend;
private final PluginSetContext<ExternalIncludedIn> externalIncludedIn;
@Inject
IncludedIn(
- GitRepositoryManager repoManager, PluginSetContext<ExternalIncludedIn> externalIncludedIn) {
+ GitRepositoryManager repoManager,
+ PermissionBackend permissionBackend,
+ PluginSetContext<ExternalIncludedIn> externalIncludedIn) {
this.repoManager = repoManager;
+ this.permissionBackend = permissionBackend;
this.externalIncludedIn = externalIncludedIn;
}
public IncludedInInfo apply(Project.NameKey project, String revisionId)
- throws RestApiException, IOException {
+ throws RestApiException, IOException, PermissionBackendException {
try (Repository r = repoManager.openRepository(project);
RevWalk rw = new RevWalk(r)) {
rw.setRetainBody(false);
@@ -61,18 +76,48 @@
}
IncludedInResolver.Result d = IncludedInResolver.resolve(r, rw, rev);
+
+ // Filter branches and tags according to their visbility by the user
+ ImmutableSortedSet<String> filteredBranches =
+ sortedShortNames(filterReadableRefs(project, d.branches()));
+ ImmutableSortedSet<String> filteredTags =
+ sortedShortNames(filterReadableRefs(project, d.tags()));
+
ListMultimap<String, String> external = MultimapBuilder.hashKeys().arrayListValues().build();
externalIncludedIn.runEach(
ext -> {
ListMultimap<String, String> extIncludedIns =
- ext.getIncludedIn(project.get(), rev.name(), d.tags(), d.branches());
+ ext.getIncludedIn(project.get(), rev.name(), filteredBranches, filteredTags);
if (extIncludedIns != null) {
external.putAll(extIncludedIns);
}
});
return new IncludedInInfo(
- d.branches(), d.tags(), (!external.isEmpty() ? external.asMap() : null));
+ filteredBranches, filteredTags, (!external.isEmpty() ? external.asMap() : null));
}
}
+
+ /**
+ * Filter readable branches or tags according to the caller's refs visibility.
+ *
+ * @param project specific Gerrit project.
+ * @param inputRefs a list of branches (in short name) as strings
+ */
+ private Collection<String> filterReadableRefs(
+ Project.NameKey project, ImmutableList<Ref> inputRefs)
+ throws IOException, PermissionBackendException {
+ PermissionBackend.ForProject perm = permissionBackend.currentUser().project(project);
+ try (Repository repo = repoManager.openRepository(project)) {
+ return perm.filter(inputRefs, repo, RefFilterOptions.defaults()).stream()
+ .map(Ref::getName)
+ .collect(toImmutableList());
+ }
+ }
+
+ private ImmutableSortedSet<String> sortedShortNames(Collection<String> refs) {
+ return refs.stream()
+ .map(Repository::shortenRefName)
+ .collect(toImmutableSortedSet(naturalOrder()));
+ }
}
diff --git a/java/com/google/gerrit/server/change/IncludedInResolver.java b/java/com/google/gerrit/server/change/IncludedInResolver.java
index 3e1b69b..b2b0a64 100644
--- a/java/com/google/gerrit/server/change/IncludedInResolver.java
+++ b/java/com/google/gerrit/server/change/IncludedInResolver.java
@@ -14,13 +14,11 @@
package com.google.gerrit.server.change;
-import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static java.util.Comparator.comparing;
-import static java.util.Comparator.naturalOrder;
import static java.util.stream.Collectors.toList;
import com.google.auto.value.AutoValue;
-import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
@@ -117,13 +115,12 @@
* Returns the short names of refs which are as well in the matchingRefs list as well as in the
* allRef list.
*/
- private static ImmutableSortedSet<String> getMatchingRefNames(
+ private static ImmutableList<Ref> getMatchingRefNames(
Set<String> matchingRefs, Collection<Ref> allRefs) {
return allRefs.stream()
- .map(Ref::getName)
- .filter(matchingRefs::contains)
- .map(Repository::shortenRefName)
- .collect(toImmutableSortedSet(naturalOrder()));
+ .filter(r -> matchingRefs.contains(r.getName()))
+ .distinct()
+ .collect(ImmutableList.toImmutableList());
}
/** Parse commit of ref and store the relation between ref and commit. */
@@ -157,8 +154,8 @@
@AutoValue
public abstract static class Result {
- public abstract ImmutableSortedSet<String> branches();
+ public abstract ImmutableList<Ref> branches();
- public abstract ImmutableSortedSet<String> tags();
+ public abstract ImmutableList<Ref> tags();
}
}
diff --git a/java/com/google/gerrit/server/change/LabelNormalizer.java b/java/com/google/gerrit/server/change/LabelNormalizer.java
index b5527d7..aeb9db0 100644
--- a/java/com/google/gerrit/server/change/LabelNormalizer.java
+++ b/java/com/google/gerrit/server/change/LabelNormalizer.java
@@ -77,10 +77,11 @@
}
/**
+ * Returns copies of approvals normalized to the defined ranges for the label type. Approvals for
+ * unknown labels are not included in the output
+ *
* @param notes change notes containing the given approvals.
* @param approvals list of approvals.
- * @return copies of approvals normalized to the defined ranges for the label type. Approvals for
- * unknown labels are not included in the output.
*/
public Result normalize(ChangeNotes notes, Collection<PatchSetApproval> approvals) {
List<PatchSetApproval> unchanged = Lists.newArrayListWithCapacity(approvals.size());
diff --git a/java/com/google/gerrit/server/change/PatchSetInserter.java b/java/com/google/gerrit/server/change/PatchSetInserter.java
index d25dba0..f093958 100644
--- a/java/com/google/gerrit/server/change/PatchSetInserter.java
+++ b/java/com/google/gerrit/server/change/PatchSetInserter.java
@@ -285,6 +285,11 @@
throw new BadRequestException(ex.getMessage());
}
}
+
+ // Approvals that are being set in the new patch-set during this operation are not available yet
+ // outside of the scope of this method. Only copied approvals are set here.
+ approvalsUtil.byPatchSet(ctx.getNotes(), patchSet).forEach(a -> update.putCopiedApproval(a));
+
return true;
}
diff --git a/java/com/google/gerrit/server/change/ReviewerModifier.java b/java/com/google/gerrit/server/change/ReviewerModifier.java
index f3c5193..fffb107 100644
--- a/java/com/google/gerrit/server/change/ReviewerModifier.java
+++ b/java/com/google/gerrit/server/change/ReviewerModifier.java
@@ -201,9 +201,6 @@
* @return handle describing the addition operation. If the {@code op} field is present, this
* operation may be added to a {@code BatchUpdate}. Otherwise, the {@code error} field
* contains information about an error that occurred
- * @throws IOException
- * @throws PermissionBackendException
- * @throws ConfigInvalidException
*/
public ReviewerModification prepare(
ChangeNotes notes, CurrentUser user, ReviewerInput input, boolean allowGroup)
diff --git a/java/com/google/gerrit/server/config/AllProjectsConfigProvider.java b/java/com/google/gerrit/server/config/AllProjectsConfigProvider.java
new file mode 100644
index 0000000..27ae41f
--- /dev/null
+++ b/java/com/google/gerrit/server/config/AllProjectsConfigProvider.java
@@ -0,0 +1,8 @@
+package com.google.gerrit.server.config;
+
+import java.util.Optional;
+import org.eclipse.jgit.lib.StoredConfig;
+
+public interface AllProjectsConfigProvider {
+ Optional<StoredConfig> get(AllProjectsName allProjectsName);
+}
diff --git a/java/com/google/gerrit/server/config/AuthConfig.java b/java/com/google/gerrit/server/config/AuthConfig.java
index de57d04..1760378 100644
--- a/java/com/google/gerrit/server/config/AuthConfig.java
+++ b/java/com/google/gerrit/server/config/AuthConfig.java
@@ -64,6 +64,7 @@
private final boolean cookieSecure;
private final SignedToken emailReg;
private final boolean allowRegisterNewEmail;
+ private final boolean userNameCaseInsensitive;
private GitBasicAuthPolicy gitBasicAuthPolicy;
@Inject
@@ -95,6 +96,7 @@
useContributorAgreements = cfg.getBoolean("auth", "contributoragreements", false);
userNameToLowerCase = cfg.getBoolean("auth", "userNameToLowerCase", false);
allowRegisterNewEmail = cfg.getBoolean("auth", "allowRegisterNewEmail", true);
+ userNameCaseInsensitive = cfg.getBoolean("auth", "userNameCaseInsensitive", false);
if (gitBasicAuthPolicy == GitBasicAuthPolicy.HTTP_LDAP
&& authType != AuthType.LDAP
@@ -227,7 +229,7 @@
return trustContainerAuth;
}
- /** @return true if users with Run As capability can impersonate others. */
+ /** Returns true if users with Run As capability can impersonate others. */
public boolean isRunAsEnabled() {
return enableRunAs;
}
@@ -237,6 +239,11 @@
return userNameToLowerCase;
}
+ /** Whether user name should be matched case insenitive */
+ public boolean isUserNameCaseInsensitive() {
+ return userNameCaseInsensitive;
+ }
+
public GitBasicAuthPolicy getGitBasicAuthPolicy() {
return gitBasicAuthPolicy;
}
diff --git a/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java b/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
index b37e489..4032e63 100644
--- a/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
+++ b/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
@@ -32,9 +32,9 @@
* <p>1. Help the callers figure out if any action should be taken, depending on which entries are
* updated in gerrit.config.
*
- * <p>2. Provide the callers with a mechanism to accept/reject the entries of interest: @see
- * accept(Set<ConfigKey> entries), @see accept(String section), @see reject(Set<ConfigKey> entries)
- * (+ various overloaded versions of these)
+ * <p>2. Provide the callers with a mechanism to accept/reject the entries of interest: {@link
+ * #accept(Set)}, {@link #accept(String)}, {@link #reject(Set)} (+ various overloaded versions of
+ * these)
*/
public class ConfigUpdatedEvent {
public static final ImmutableMultimap<UpdateResult, ConfigUpdateEntry> NO_UPDATES =
diff --git a/java/com/google/gerrit/server/config/ConfigUtil.java b/java/com/google/gerrit/server/config/ConfigUtil.java
index 27ded63..c44b0fd 100644
--- a/java/com/google/gerrit/server/config/ConfigUtil.java
+++ b/java/com/google/gerrit/server/config/ConfigUtil.java
@@ -282,7 +282,6 @@
* @param sub subsection
* @param s instance of class with config values
* @param defaults instance of class with default values
- * @throws ConfigInvalidException
*/
public static <T> void storeSection(Config cfg, String section, String sub, T s, T defaults)
throws ConfigInvalidException {
@@ -341,7 +340,6 @@
* @param i instance to merge during the load. When present, the boolean fields are not nullified
* when their values are false
* @return loaded instance
- * @throws ConfigInvalidException
*/
public static <T> T loadSection(Config cfg, String section, String sub, T s, T defaults, T i)
throws ConfigInvalidException {
diff --git a/java/com/google/gerrit/server/config/FileBasedAllProjectsConfigProvider.java b/java/com/google/gerrit/server/config/FileBasedAllProjectsConfigProvider.java
new file mode 100644
index 0000000..ebb0e50
--- /dev/null
+++ b/java/com/google/gerrit/server/config/FileBasedAllProjectsConfigProvider.java
@@ -0,0 +1,33 @@
+package com.google.gerrit.server.config;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.gerrit.server.project.ProjectConfig;
+import com.google.inject.Inject;
+import java.util.Optional;
+import javax.inject.Singleton;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+
+@Singleton
+public class FileBasedAllProjectsConfigProvider implements AllProjectsConfigProvider {
+ private final SitePaths sitePaths;
+
+ @VisibleForTesting
+ @Inject
+ public FileBasedAllProjectsConfigProvider(SitePaths sitePaths) {
+ this.sitePaths = sitePaths;
+ }
+
+ @Override
+ public Optional<StoredConfig> get(AllProjectsName allProjectsName) {
+ return Optional.of(
+ new FileBasedConfig(
+ sitePaths
+ .etc_dir
+ .resolve(allProjectsName.get())
+ .resolve(ProjectConfig.PROJECT_CONFIG)
+ .toFile(),
+ FS.DETECTED));
+ }
+}
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index ac4a8d9..35b16b4 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -85,6 +85,7 @@
import com.google.gerrit.server.ExceptionHookImpl;
import com.google.gerrit.server.ExternalUser;
import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.PerformanceMetrics;
import com.google.gerrit.server.RequestListener;
import com.google.gerrit.server.TraceRequestListener;
import com.google.gerrit.server.account.AccountCacheImpl;
@@ -92,6 +93,8 @@
import com.google.gerrit.server.account.AccountDeactivator;
import com.google.gerrit.server.account.AccountExternalIdCreator;
import com.google.gerrit.server.account.AccountManager;
+import com.google.gerrit.server.account.AccountModule;
+import com.google.gerrit.server.account.AccountTagProvider;
import com.google.gerrit.server.account.AccountVisibilityProvider;
import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.account.EmailExpander;
@@ -100,6 +103,7 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.ServiceUserClassifierImpl;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
+import com.google.gerrit.server.account.externalids.ExternalIdCacheModule;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
import com.google.gerrit.server.approval.ApprovalCacheImpl;
@@ -130,6 +134,7 @@
import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.git.MergedByPushOp;
+import com.google.gerrit.server.git.MultiProgressMonitor;
import com.google.gerrit.server.git.NotesBranchUtil;
import com.google.gerrit.server.git.PureRevertCache;
import com.google.gerrit.server.git.ReceivePackInitializer;
@@ -182,6 +187,7 @@
import com.google.gerrit.server.project.ProjectCacheImpl;
import com.google.gerrit.server.project.ProjectNameLockManager;
import com.google.gerrit.server.project.ProjectState;
+import com.google.gerrit.server.project.SubmitRequirementsEvaluatorImpl;
import com.google.gerrit.server.project.SubmitRuleEvaluator;
import com.google.gerrit.server.query.approval.ApprovalModule;
import com.google.gerrit.server.query.change.ChangeData;
@@ -260,10 +266,13 @@
install(TagCache.module());
install(PureRevertCache.module());
install(CommentContextCacheImpl.module());
+ install(SubmitRequirementsEvaluatorImpl.module());
install(new AccessControlModule());
+ install(new AccountModule());
install(new CmdLineParserModule());
install(new EmailModule());
+ install(new ExternalIdCacheModule());
install(new ExternalIdModule());
install(new GitModule());
install(new GroupDbModule());
@@ -284,6 +293,7 @@
factory(ChangeIsVisibleToPredicate.Factory.class);
factory(DeadlineChecker.Factory.class);
factory(MergeUtil.Factory.class);
+ factory(MultiProgressMonitor.Factory.class);
factory(PatchScriptFactory.Factory.class);
factory(PatchScriptFactoryForAutoFix.Factory.class);
factory(ProjectState.Factory.class);
@@ -422,6 +432,7 @@
DynamicSet.setOf(binder(), SubmitRule.class);
DynamicSet.setOf(binder(), QuotaEnforcer.class);
DynamicSet.setOf(binder(), PerformanceLogger.class);
+ DynamicSet.bind(binder(), PerformanceLogger.class).to(PerformanceMetrics.class);
DynamicSet.setOf(binder(), RequestListener.class);
DynamicSet.bind(binder(), RequestListener.class).to(TraceRequestListener.class);
DynamicSet.setOf(binder(), ChangeETagComputation.class);
@@ -429,6 +440,7 @@
DynamicSet.bind(binder(), ExceptionHook.class).to(ExceptionHookImpl.class);
DynamicSet.setOf(binder(), MailSoyTemplateProvider.class);
DynamicSet.setOf(binder(), OnPostReview.class);
+ DynamicMap.mapOf(binder(), AccountTagProvider.class);
DynamicMap.mapOf(binder(), MailFilter.class);
bind(MailFilter.class).annotatedWith(Exports.named("ListMailFilter")).to(ListMailFilter.class);
diff --git a/java/com/google/gerrit/server/config/GerritIsReplica.java b/java/com/google/gerrit/server/config/GerritIsReplica.java
index 154fdcd..ab6aa8b 100644
--- a/java/com/google/gerrit/server/config/GerritIsReplica.java
+++ b/java/com/google/gerrit/server/config/GerritIsReplica.java
@@ -19,7 +19,7 @@
import com.google.inject.BindingAnnotation;
import java.lang.annotation.Retention;
-/* Marker on {@link Boolean} indicating whether Gerrit is run as a read-only replica. */
+/** Marker on {@link Boolean} indicating whether Gerrit is run as a read-only replica. */
@Retention(RUNTIME)
@BindingAnnotation
public @interface GerritIsReplica {}
diff --git a/java/com/google/gerrit/server/config/GerritServerConfigModule.java b/java/com/google/gerrit/server/config/GerritServerConfigModule.java
index da85834..8ddcdac 100644
--- a/java/com/google/gerrit/server/config/GerritServerConfigModule.java
+++ b/java/com/google/gerrit/server/config/GerritServerConfigModule.java
@@ -66,6 +66,7 @@
bind(Config.class)
.annotatedWith(GerritServerConfig.class)
.toProvider(GerritServerConfigProvider.class);
+ bind(AllProjectsConfigProvider.class).to(FileBasedAllProjectsConfigProvider.class);
bind(GlobalPluginConfigProvider.class).to(FileBasedGlobalPluginConfigProvider.class);
bind(SecureStore.class).toProvider(SecureStoreProvider.class).in(SINGLETON);
bind(Boolean.class)
diff --git a/java/com/google/gerrit/server/config/GitwebCgiConfig.java b/java/com/google/gerrit/server/config/GitwebCgiConfig.java
index d7fb83c..1ed0f16 100644
--- a/java/com/google/gerrit/server/config/GitwebCgiConfig.java
+++ b/java/com/google/gerrit/server/config/GitwebCgiConfig.java
@@ -118,22 +118,22 @@
this.logoPng = null;
}
- /** @return local path to the CGI executable; null if we shouldn't execute. */
+ /** Returns local path to the CGI executable; null if we shouldn't execute. */
public Path getGitwebCgi() {
return cgi;
}
- /** @return local path of the {@code gitweb.css} matching the CGI. */
+ /** Returns local path of the {@code gitweb.css} matching the CGI. */
public Path getGitwebCss() {
return css;
}
- /** @return local path of the {@code gitweb.js} for the CGI. */
+ /** Returns local path of the {@code gitweb.js} for the CGI. */
public Path getGitwebJs() {
return js;
}
- /** @return local path of the {@code git-logo.png} for the CGI. */
+ /** Returns local path of the {@code git-logo.png} for the CGI. */
public Path getGitLogoPng() {
return logoPng;
}
diff --git a/java/com/google/gerrit/server/config/GitwebConfig.java b/java/com/google/gerrit/server/config/GitwebConfig.java
index f90a72e..5632978 100644
--- a/java/com/google/gerrit/server/config/GitwebConfig.java
+++ b/java/com/google/gerrit/server/config/GitwebConfig.java
@@ -213,16 +213,16 @@
}
}
- /** @return GitwebType for gitweb viewer. */
+ /** Returns GitwebType for gitweb viewer. */
@Nullable
public GitwebType getGitwebType() {
return type;
}
/**
- * @return URL of the entry point into gitweb. This URL may be relative to our context if gitweb
- * is hosted by ourselves; or absolute if its hosted elsewhere; or null if gitweb has not been
- * configured.
+ * Returns URL of the entry point into gitweb. This URL may be relative to our context if gitweb
+ * is hosted by ourselves; or absolute if its hosted elsewhere; or null if gitweb has not been
+ * configured.
*/
public String getUrl() {
return url;
diff --git a/java/com/google/gerrit/server/config/ProjectConfigEntry.java b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
index fcfa5e9..c09988e3 100644
--- a/java/com/google/gerrit/server/config/ProjectConfigEntry.java
+++ b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
@@ -206,16 +206,18 @@
}
/**
+ * Returns whether the project is editable
+ *
* @param project project state.
- * @return whether the project is editable.
*/
public boolean isEditable(ProjectState project) {
return true;
}
/**
+ * Returns any warning associated with the project
+ *
* @param project project state.
- * @return any warning associated with the project.
*/
public String getWarning(ProjectState project) {
return null;
diff --git a/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index 710916e..6b018ce 100644
--- a/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -146,9 +146,6 @@
* @param edit change edit to publish
* @param notify Notify handling that defines to whom email notifications should be sent after the
* change edit is published.
- * @throws IOException
- * @throws UpdateException
- * @throws RestApiException
*/
public void publish(
BatchUpdate.Factory updateFactory,
@@ -209,7 +206,6 @@
* Delete change edit.
*
* @param edit change edit to delete
- * @throws IOException
*/
public void delete(ChangeEdit edit) throws IOException {
Change change = edit.getChange();
diff --git a/java/com/google/gerrit/server/events/EventsMetrics.java b/java/com/google/gerrit/server/events/EventsMetrics.java
index 3c87cca..6d48c37 100644
--- a/java/com/google/gerrit/server/events/EventsMetrics.java
+++ b/java/com/google/gerrit/server/events/EventsMetrics.java
@@ -32,7 +32,9 @@
metricMaker.newCounter(
"events",
new Description("Triggered events").setRate().setUnit("triggered events"),
- Field.ofString("type", Metadata.Builder::eventType).build());
+ Field.ofString("type", Metadata.Builder::eventType)
+ .description("The type of the event.")
+ .build());
}
@Override
diff --git a/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java b/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java
index 65662ba..b060d3e 100644
--- a/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java
+++ b/java/com/google/gerrit/server/experiments/ExperimentFeaturesConstants.java
@@ -26,11 +26,12 @@
"GerritBackendRequestFeature__remove_revision_etag";
/**
- * Whether git pushes are cancelled if the client disconnects or the configured receive.timeout is
- * exceeded.
+ * Allow legacy {@link com.google.gerrit.entities.SubmitRecord}s to be converted and returned as
+ * submit requirements by the {@link
+ * com.google.gerrit.server.project.SubmitRequirementsEvaluator}.
*/
- public static final String GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_PUSH_CANCELLATION =
- "GerritBackendRequestFeature__enable_push_cencallation";
+ public static final String GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_LEGACY_SUBMIT_REQUIREMENTS =
+ "GerritBackendRequestFeature__enable_legacy_submit_requirements";
/** Features, enabled by default in the current release. */
public static final ImmutableSet<String> DEFAULT_ENABLED_FEATURES =
diff --git a/java/com/google/gerrit/server/extensions/webui/UiActions.java b/java/com/google/gerrit/server/extensions/webui/UiActions.java
index a7f6b48..34c3c20 100644
--- a/java/com/google/gerrit/server/extensions/webui/UiActions.java
+++ b/java/com/google/gerrit/server/extensions/webui/UiActions.java
@@ -72,7 +72,9 @@
new com.google.gerrit.metrics.Description("Latency for RestView#getDescription calls")
.setCumulative()
.setUnit(Units.MILLISECONDS),
- Field.ofString("view", Metadata.Builder::restViewName).build());
+ Field.ofString("view", Metadata.Builder::restViewName)
+ .description("view implementation class")
+ .build());
}
public <R extends RestResource> Iterable<UiAction.Description> from(
diff --git a/java/com/google/gerrit/server/git/DelegateRefDatabase.java b/java/com/google/gerrit/server/git/DelegateRefDatabase.java
index decae05..bc5dd00 100644
--- a/java/com/google/gerrit/server/git/DelegateRefDatabase.java
+++ b/java/com/google/gerrit/server/git/DelegateRefDatabase.java
@@ -15,10 +15,12 @@
package com.google.gerrit.server.git;
import java.io.IOException;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.annotations.NonNull;
+import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefDatabase;
@@ -34,7 +36,7 @@
private Repository delegate;
- DelegateRefDatabase(Repository delegate) {
+ public DelegateRefDatabase(Repository delegate) {
this.delegate = delegate;
}
@@ -49,11 +51,21 @@
}
@Override
+ public boolean hasVersioning() {
+ return delegate.getRefDatabase().hasVersioning();
+ }
+
+ @Override
public boolean isNameConflicting(String name) throws IOException {
return delegate.getRefDatabase().isNameConflicting(name);
}
@Override
+ public Collection<String> getConflictingNames(String name) throws IOException {
+ return delegate.getRefDatabase().getConflictingNames(name);
+ }
+
+ @Override
public RefUpdate newUpdate(String name, boolean detach) throws IOException {
return delegate.getRefDatabase().newUpdate(name, detach);
}
@@ -64,10 +76,35 @@
}
@Override
+ public BatchRefUpdate newBatchUpdate() {
+ return delegate.getRefDatabase().newBatchUpdate();
+ }
+
+ @Override
+ public boolean performsAtomicTransactions() {
+ return delegate.getRefDatabase().performsAtomicTransactions();
+ }
+
+ @Override
public Ref exactRef(String name) throws IOException {
return delegate.getRefDatabase().exactRef(name);
}
+ @Override
+ public Map<String, Ref> exactRef(String... refs) throws IOException {
+ return delegate.getRefDatabase().exactRef(refs);
+ }
+
+ @Override
+ public Ref firstExactRef(String... refs) throws IOException {
+ return delegate.getRefDatabase().firstExactRef(refs);
+ }
+
+ @Override
+ public List<Ref> getRefs() throws IOException {
+ return delegate.getRefDatabase().getRefs();
+ }
+
@SuppressWarnings("deprecation")
@Override
public Map<String, Ref> getRefs(String prefix) throws IOException {
@@ -75,12 +112,38 @@
}
@Override
+ public List<Ref> getRefsByPrefix(String prefix) throws IOException {
+ return delegate.getRefDatabase().getRefsByPrefix(prefix);
+ }
+
+ @Override
+ public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
+ throws IOException {
+ return delegate.getRefDatabase().getRefsByPrefixWithExclusions(include, excludes);
+ }
+
+ @Override
+ public List<Ref> getRefsByPrefix(String... prefixes) throws IOException {
+ return delegate.getRefDatabase().getRefsByPrefix(prefixes);
+ }
+
+ @Override
@NonNull
public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
return delegate.getRefDatabase().getTipsWithSha1(id);
}
@Override
+ public boolean hasFastTipsWithSha1() throws IOException {
+ return delegate.getRefDatabase().hasFastTipsWithSha1();
+ }
+
+ @Override
+ public boolean hasRefs() throws IOException {
+ return delegate.getRefDatabase().hasRefs();
+ }
+
+ @Override
public List<Ref> getAdditionalRefs() throws IOException {
return delegate.getRefDatabase().getAdditionalRefs();
}
@@ -90,7 +153,12 @@
return delegate.getRefDatabase().peel(ref);
}
- Repository getDelegate() {
+ @Override
+ public void refresh() {
+ delegate.getRefDatabase().refresh();
+ }
+
+ protected Repository getDelegate() {
return delegate;
}
}
diff --git a/java/com/google/gerrit/server/git/GitRepositoryManager.java b/java/com/google/gerrit/server/git/GitRepositoryManager.java
index e4d0696..8dba3e1 100644
--- a/java/com/google/gerrit/server/git/GitRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/GitRepositoryManager.java
@@ -30,6 +30,23 @@
*/
@ImplementedBy(value = LocalDiskRepositoryManager.class)
public interface GitRepositoryManager {
+
+ /** Status of the repository. */
+ enum Status {
+ /** Repository exists and is available on host. */
+ ACTIVE,
+ /** Repository does not exist. */
+ NON_EXISTENT,
+ /**
+ * Repository might exist but can not be opened. This can for example be the case when the
+ * repository is pending deletion / the caller does not have permissions / repository is broken.
+ */
+ UNAVAILABLE;
+ }
+
+ /** Get {@link Status} of the repository by name. */
+ Status getRepositoryStatus(Project.NameKey name);
+
/**
* Get (or open) a repository by name.
*
@@ -47,15 +64,16 @@
* @param name the repository name, relative to the base directory.
* @return the cached Repository instance. Caller must call {@code close()} when done to decrement
* the resource handle.
+ * @throws RepositoryExistsException repository exists.
* @throws RepositoryCaseMismatchException the name collides with an existing repository name, but
* only in case of a character within the name.
* @throws RepositoryNotFoundException the name is invalid.
* @throws IOException the repository cannot be created.
*/
Repository createRepository(Project.NameKey name)
- throws RepositoryCaseMismatchException, RepositoryNotFoundException, IOException;
+ throws RepositoryNotFoundException, RepositoryExistsException, IOException;
- /** @return set of all known projects, sorted by natural NameKey order. */
+ /** Returns set of all known projects, sorted by natural NameKey order. */
SortedSet<Project.NameKey> list();
/**
diff --git a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index 10220d8..1dc5c16 100644
--- a/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -16,6 +16,7 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.lifecycle.LifecycleModule;
@@ -128,6 +129,29 @@
}
@Override
+ public Status getRepositoryStatus(NameKey name) {
+ if (isUnreasonableName(name)) {
+ return Status.NON_EXISTENT;
+ }
+ Path path = getBasePath(name);
+ File dir = FileKey.resolve(path.resolve(name.get()).toFile(), FS.DETECTED);
+ if (dir == null) {
+ return Status.NON_EXISTENT;
+ }
+ Repository repo;
+ try {
+ // Try to open with mustExist, so that it does not attempt to create a repository.
+ repo = RepositoryCache.open(FileKey.lenient(dir, FS.DETECTED), /*mustExist=*/ true);
+ } catch (RepositoryNotFoundException e) {
+ return Status.NON_EXISTENT;
+ } catch (IOException e) {
+ return Status.UNAVAILABLE;
+ }
+ // If object database does not exist, the repository is unusable
+ return repo.getObjectDatabase().exists() ? Status.ACTIVE : Status.UNAVAILABLE;
+ }
+
+ @Override
public Repository openRepository(Project.NameKey name) throws RepositoryNotFoundException {
return openRepository(getBasePath(name), name);
}
@@ -147,7 +171,7 @@
@Override
public Repository createRepository(Project.NameKey name)
- throws RepositoryNotFoundException, RepositoryCaseMismatchException, IOException {
+ throws RepositoryNotFoundException, RepositoryExistsException, IOException {
if (isUnreasonableName(name)) {
throw new RepositoryNotFoundException("Invalid name: " + name);
}
@@ -162,8 +186,7 @@
if (!onDiskName.equals(name)) {
throw new RepositoryCaseMismatchException(name);
}
-
- throw new IllegalStateException("Repository already exists: " + name);
+ throw new RepositoryExistsException(name);
}
// It doesn't exist under any of the standard permutations
diff --git a/java/com/google/gerrit/server/git/MergeTip.java b/java/com/google/gerrit/server/git/MergeTip.java
index 204f453..4ffa1a8 100644
--- a/java/com/google/gerrit/server/git/MergeTip.java
+++ b/java/com/google/gerrit/server/git/MergeTip.java
@@ -52,8 +52,8 @@
}
/**
- * @return the initial tip of the branch before the merge operation started; may be null,
- * indicating a previously unborn branch.
+ * Returns the initial tip of the branch before the merge operation started; may be null,
+ * indicating a previously unborn branch.
*/
public CodeReviewCommit getInitialTip() {
return initialTip;
@@ -82,8 +82,8 @@
}
/**
- * @return The current tip of the current merge operation; may be null, indicating an unborn
- * branch.
+ * Returns The current tip of the current merge operation; may be null, indicating an unborn
+ * branch.
*/
@Nullable
public CodeReviewCommit getCurrentTip() {
diff --git a/java/com/google/gerrit/server/git/MergeUtil.java b/java/com/google/gerrit/server/git/MergeUtil.java
index 3385969..3a4d407 100644
--- a/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/java/com/google/gerrit/server/git/MergeUtil.java
@@ -512,9 +512,6 @@
* <li>Change-Id
* </ul>
*
- * @param n
- * @param notes
- * @param psId
* @return new message
*/
private String createDetailedCommitMessage(RevCommit n, ChangeNotes notes, PatchSet.Id psId) {
@@ -630,10 +627,6 @@
* Plugins implementing {@link ChangeMessageModifier} can modify the resulting commit message
* arbitrarily.
*
- * @param n
- * @param mergeTip
- * @param notes
- * @param id
* @return new message
*/
public String createCommitMessageOnSubmit(
diff --git a/java/com/google/gerrit/server/git/MultiProgressMonitor.java b/java/com/google/gerrit/server/git/MultiProgressMonitor.java
index 22385c7..a4b1033 100644
--- a/java/com/google/gerrit/server/git/MultiProgressMonitor.java
+++ b/java/com/google/gerrit/server/git/MultiProgressMonitor.java
@@ -14,16 +14,17 @@
package com.google.gerrit.server.git;
-import static com.google.gerrit.server.DeadlineChecker.TIMEOUT_FORMATTER;
+import static com.google.gerrit.server.DeadlineChecker.getTimeoutFormatter;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.util.concurrent.UncheckedExecutionException;
+import com.google.gerrit.server.CancellationMetrics;
import com.google.gerrit.server.cancellation.RequestStateProvider;
-import com.google.gerrit.server.experiments.ExperimentFeatures;
-import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
+import com.google.inject.assistedinject.Assisted;
+import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
@@ -80,6 +81,11 @@
private static final char[] SPINNER_STATES = new char[] {'-', '\\', '|', '/'};
private static final char NO_SPINNER = ' ';
+ public enum TaskKind {
+ INDEXING,
+ RECEIVE_COMMITS;
+ }
+
/** Handle for a sub-task. */
public class Task implements ProgressMonitor {
private final String name;
@@ -149,8 +155,20 @@
}
}
- private final ExperimentFeatures experimentFeatures;
+ public interface Factory {
+ MultiProgressMonitor create(OutputStream out, TaskKind taskKind, String taskName);
+
+ MultiProgressMonitor create(
+ OutputStream out,
+ TaskKind taskKind,
+ String taskName,
+ long maxIntervalTime,
+ TimeUnit maxIntervalUnit);
+ }
+
+ private final CancellationMetrics cancellationMetrics;
private final OutputStream out;
+ private final TaskKind taskKind;
private final String taskName;
private final List<Task> tasks = new CopyOnWriteArrayList<>();
private int spinnerIndex;
@@ -158,6 +176,7 @@
private boolean done;
private boolean clientDisconnected;
private boolean deadlineExceeded;
+ private boolean forcefulTermination;
private Optional<Long> timeout = Optional.empty();
private final long maxIntervalNanos;
@@ -168,9 +187,13 @@
* @param out stream for writing progress messages.
* @param taskName name of the overall task.
*/
- public MultiProgressMonitor(
- ExperimentFeatures experimentFeatures, OutputStream out, String taskName) {
- this(experimentFeatures, out, taskName, 500, MILLISECONDS);
+ @AssistedInject
+ private MultiProgressMonitor(
+ CancellationMetrics cancellationMetrics,
+ @Assisted OutputStream out,
+ @Assisted TaskKind taskKind,
+ @Assisted String taskName) {
+ this(cancellationMetrics, out, taskKind, taskName, 500, MILLISECONDS);
}
/**
@@ -181,14 +204,17 @@
* @param maxIntervalTime maximum interval between progress messages.
* @param maxIntervalUnit time unit for progress interval.
*/
- public MultiProgressMonitor(
- ExperimentFeatures experimentFeatures,
- OutputStream out,
- String taskName,
- long maxIntervalTime,
- TimeUnit maxIntervalUnit) {
- this.experimentFeatures = experimentFeatures;
+ @AssistedInject
+ private MultiProgressMonitor(
+ CancellationMetrics cancellationMetrics,
+ @Assisted OutputStream out,
+ @Assisted TaskKind taskKind,
+ @Assisted String taskName,
+ @Assisted long maxIntervalTime,
+ @Assisted TimeUnit maxIntervalUnit) {
+ this.cancellationMetrics = cancellationMetrics;
this.out = out;
+ this.taskKind = taskKind;
this.taskName = taskName;
maxIntervalNanos = NANOSECONDS.convert(maxIntervalTime, maxIntervalUnit);
}
@@ -264,10 +290,14 @@
long now = System.nanoTime();
if (deadline > 0 && now > deadline) {
- logger.atFine().log(
- "deadline exceeded after %sms: (timeout %sms, signaling cancellation)",
- MILLISECONDS.convert(now - overallStart, NANOSECONDS),
- MILLISECONDS.convert(now - deadline, NANOSECONDS));
+ if (!deadlineExceeded) {
+ logger.atFine().log(
+ "deadline exceeded after %sms, signaling cancellation (timeout=%sms, task=%s(%s))",
+ MILLISECONDS.convert(now - overallStart, NANOSECONDS),
+ MILLISECONDS.convert(now - deadline, NANOSECONDS),
+ taskKind,
+ taskName);
+ }
deadlineExceeded = true;
// After setting deadlineExceeded = true give the cancellationNanos to react to the
@@ -275,11 +305,17 @@
if (now > deadline + cancellationNanos) {
// The worker didn't react to the cancellation, cancel it forcefully by an interrupt.
workerFuture.cancel(true);
+ forcefulTermination = true;
if (workerFuture.isCancelled()) {
logger.atWarning().log(
- "MultiProgressMonitor worker killed after %sms: (timeout %sms, cancelled)",
+ "MultiProgressMonitor worker killed after %sms, cancelled (timeout=%sms, task=%s(%s))",
MILLISECONDS.convert(now - overallStart, NANOSECONDS),
- MILLISECONDS.convert(now - deadline, NANOSECONDS));
+ MILLISECONDS.convert(now - deadline, NANOSECONDS),
+ taskKind,
+ taskName);
+ if (taskKind == TaskKind.RECEIVE_COMMITS) {
+ cancellationMetrics.countForcefulReceiveTimeout();
+ }
}
break;
}
@@ -294,10 +330,15 @@
if (!done && workerFuture.isDone()) {
// The worker may not have called end() explicitly, which is likely a
// programming error.
- logger.atWarning().log("MultiProgressMonitor worker did not call end() before returning");
+ logger.atWarning().log(
+ "MultiProgressMonitor worker did not call end() before returning (task=%s(%s))",
+ taskKind, taskName);
end();
}
}
+ if (deadlineExceeded && !forcefulTermination && taskKind == TaskKind.RECEIVE_COMMITS) {
+ cancellationMetrics.countGracefulReceiveTimeout();
+ }
sendDone();
}
@@ -306,7 +347,8 @@
try {
return workerFuture.get(maxIntervalNanos, NANOSECONDS);
} catch (InterruptedException | CancellationException e) {
- logger.atWarning().withCause(e).log("unable to finish processing");
+ logger.atWarning().withCause(e).log(
+ "unable to finish processing (task=%s(%s))", taskKind, taskName);
throw new UncheckedExecutionException(e);
} catch (TimeoutException e) {
workerFuture.cancel(true);
@@ -412,7 +454,8 @@
out.flush();
} catch (IOException e) {
logger.atWarning().withCause(e).log(
- "Sending progress to client failed. Stop sending updates for task %s", taskName);
+ "Sending progress to client failed. Stop sending updates for task %s(%s)",
+ taskKind, taskName);
clientDisconnected = true;
}
}
@@ -420,17 +463,17 @@
@Override
public void checkIfCancelled(OnCancelled onCancelled) {
- if (!experimentFeatures.isFeatureEnabled(
- ExperimentFeaturesConstants.GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_PUSH_CANCELLATION)) {
- return;
- }
-
if (clientDisconnected) {
onCancelled.onCancel(RequestStateProvider.Reason.CLIENT_CLOSED_REQUEST, /* message= */ null);
} else if (deadlineExceeded) {
onCancelled.onCancel(
RequestStateProvider.Reason.SERVER_DEADLINE_EXCEEDED,
- timeout.map(TIMEOUT_FORMATTER).orElse(null));
+ timeout
+ .map(
+ taskKind == TaskKind.RECEIVE_COMMITS
+ ? getTimeoutFormatter("receive.timeout")
+ : getTimeoutFormatter("timeout"))
+ .orElse(null));
}
}
}
diff --git a/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java b/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java
index b7dc2b3..99a66f8 100644
--- a/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java
+++ b/java/com/google/gerrit/server/git/PermissionAwareReadOnlyRefDatabase.java
@@ -24,6 +24,7 @@
import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
import com.google.gerrit.server.permissions.PermissionBackendException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -33,8 +34,10 @@
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefRename;
@@ -61,6 +64,11 @@
}
@Override
+ public Collection<String> getConflictingNames(String name) throws IOException {
+ throw new UnsupportedOperationException("PermissionAwareReadOnlyRefDatabase is read-only");
+ }
+
+ @Override
public RefUpdate newUpdate(String name, boolean detach) {
throw new UnsupportedOperationException("PermissionAwareReadOnlyRefDatabase is read-only");
}
@@ -71,6 +79,11 @@
}
@Override
+ public BatchRefUpdate newBatchUpdate() {
+ throw new UnsupportedOperationException("PermissionAwareReadOnlyRefDatabase is read-only");
+ }
+
+ @Override
public Ref exactRef(String name) throws IOException {
Ref ref = getDelegate().getRefDatabase().exactRef(name);
if (ref == null) {
@@ -148,6 +161,25 @@
}
@Override
+ public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
+ throws IOException {
+ Stream<Ref> refs = getRefs(include).values().stream();
+ for (String exclude : excludes) {
+ refs = refs.filter(r -> !r.getName().startsWith(exclude));
+ }
+ return Collections.unmodifiableList(refs.collect(Collectors.toList()));
+ }
+
+ @Override
+ public List<Ref> getRefsByPrefix(String... prefixes) throws IOException {
+ List<Ref> result = new ArrayList<>();
+ for (String prefix : prefixes) {
+ result.addAll(getRefsByPrefix(prefix));
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ @Override
@NonNull
public Map<String, Ref> exactRef(String... refs) throws IOException {
Map<String, Ref> result = new HashMap<>(refs.length);
@@ -173,6 +205,11 @@
}
@Override
+ public List<Ref> getRefs() throws IOException {
+ return getRefsByPrefix(ALL);
+ }
+
+ @Override
@NonNull
public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
Set<Ref> unfiltered = super.getTipsWithSha1(id);
@@ -184,4 +221,9 @@
}
return result;
}
+
+ @Override
+ public boolean hasRefs() throws IOException {
+ return !getRefs().isEmpty();
+ }
}
diff --git a/java/com/google/gerrit/server/git/RepoRefCache.java b/java/com/google/gerrit/server/git/RepoRefCache.java
index 6b2493a..c69f9a6 100644
--- a/java/com/google/gerrit/server/git/RepoRefCache.java
+++ b/java/com/google/gerrit/server/git/RepoRefCache.java
@@ -46,7 +46,7 @@
return id;
}
- /** @return an unmodifiable view of the refs that have been cached by this instance. */
+ /** Returns an unmodifiable view of the refs that have been cached by this instance. */
public Map<String, Optional<ObjectId>> getCachedRefs() {
return Collections.unmodifiableMap(ids);
}
diff --git a/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java b/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
index 8535cd2..9e10c67 100644
--- a/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
+++ b/java/com/google/gerrit/server/git/RepositoryCaseMismatchException.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.git;
import com.google.gerrit.entities.Project;
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
/**
* This exception is thrown if a project cannot be created because a project with the same name in a
@@ -23,12 +22,12 @@
* (e.g. Windows), because in this case the name for the git repository in the file system is
* already occupied by the existing project.
*/
-public class RepositoryCaseMismatchException extends RepositoryNotFoundException {
+public class RepositoryCaseMismatchException extends RepositoryExistsException {
private static final long serialVersionUID = 1L;
/** @param projectName name of the project that cannot be created */
public RepositoryCaseMismatchException(Project.NameKey projectName) {
- super("Name occupied in other case. Project " + projectName.get() + " cannot be created.");
+ super(projectName, "Name occupied in other case.");
}
}
diff --git a/java/com/google/gerrit/server/git/RepositoryExistsException.java b/java/com/google/gerrit/server/git/RepositoryExistsException.java
new file mode 100644
index 0000000..563b078
--- /dev/null
+++ b/java/com/google/gerrit/server/git/RepositoryExistsException.java
@@ -0,0 +1,37 @@
+// 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.git;
+
+import com.google.gerrit.entities.Project;
+import java.io.IOException;
+
+/** Thrown when trying to create a repository that exist. */
+public class RepositoryExistsException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * @param projectName name of the project that cannot be created
+ * @param reason reason why the project cannot be created
+ */
+ public RepositoryExistsException(Project.NameKey projectName, String reason) {
+ super(
+ String.format("Repository %s exists and cannot be created. %s", projectName.get(), reason));
+ }
+
+ /** @param projectName name of the project that cannot be created */
+ public RepositoryExistsException(Project.NameKey projectName) {
+ super(String.format("Repository %s exists and cannot be created.", projectName.get()));
+ }
+}
diff --git a/java/com/google/gerrit/server/git/TransferConfig.java b/java/com/google/gerrit/server/git/TransferConfig.java
index 55b9448..728e4ed 100644
--- a/java/com/google/gerrit/server/git/TransferConfig.java
+++ b/java/com/google/gerrit/server/git/TransferConfig.java
@@ -52,7 +52,7 @@
packConfig.fromConfig(cfg);
}
- /** @return configured timeout, in seconds. 0 if the timeout is infinite. */
+ /** Returns configured timeout, in seconds. 0 if the timeout is infinite. */
public int getTimeout() {
return timeout;
}
diff --git a/java/com/google/gerrit/server/git/UploadPackMetricsHook.java b/java/com/google/gerrit/server/git/UploadPackMetricsHook.java
index 4afff2b..1619add 100644
--- a/java/com/google/gerrit/server/git/UploadPackMetricsHook.java
+++ b/java/com/google/gerrit/server/git/UploadPackMetricsHook.java
@@ -45,7 +45,9 @@
@Inject
UploadPackMetricsHook(MetricMaker metricMaker) {
Field<Operation> operationField =
- Field.ofEnum(Operation.class, "operation", Metadata.Builder::gitOperation).build();
+ Field.ofEnum(Operation.class, "operation", Metadata.Builder::gitOperation)
+ .description("The name of the operation (CLONE, FETCH).")
+ .build();
requestCount =
metricMaker.newCounter(
"git/upload-pack/request_count",
diff --git a/java/com/google/gerrit/server/git/meta/MetaDataUpdate.java b/java/com/google/gerrit/server/git/meta/MetaDataUpdate.java
index e90f58b..27d5da9 100644
--- a/java/com/google/gerrit/server/git/meta/MetaDataUpdate.java
+++ b/java/com/google/gerrit/server/git/meta/MetaDataUpdate.java
@@ -160,7 +160,7 @@
return create(name, null);
}
- /** @see User#create(Project.NameKey, IdentifiedUser, BatchRefUpdate) */
+ /** See {@link User#create(Project.NameKey, IdentifiedUser, BatchRefUpdate)} */
public MetaDataUpdate create(Project.NameKey name, BatchRefUpdate batch)
throws RepositoryNotFoundException, IOException {
Repository repo = mgr.openRepository(name);
@@ -234,7 +234,7 @@
this.closeRepository = closeRepository;
}
- /** @return batch in which to run the update, or {@code null} for no batch. */
+ /** Returns batch in which to run the update, or {@code null} for no batch. */
BatchRefUpdate getBatch() {
return batch;
}
diff --git a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
index feb038a..a42ab8f 100644
--- a/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
+++ b/java/com/google/gerrit/server/git/meta/VersionedMetaData.java
@@ -35,6 +35,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheBuilder;
import org.eclipse.jgit.dircache.DirCacheEditor;
@@ -99,7 +100,7 @@
protected ObjectInserter inserter;
protected DirCache newTree;
- /** @return name of the reference storing this configuration. */
+ /** Returns name of the reference storing this configuration. */
protected abstract String getRefName();
/** Set up the metadata, parsing any state from the loaded revision. */
@@ -109,13 +110,11 @@
* Save any changes to the metadata in a commit.
*
* @return true if the commit should proceed, false to abort.
- * @throws IOException
- * @throws ConfigInvalidException
*/
protected abstract boolean onSave(CommitBuilder commit)
throws IOException, ConfigInvalidException;
- /** @return revision of the metadata that was loaded. */
+ /** Returns revision of the metadata that was loaded. */
@Nullable
public ObjectId getRevision() {
return ObjectIds.copyOrNull(revision);
@@ -129,8 +128,6 @@
*
* @param projectName the name of the project
* @param db repository to access.
- * @throws IOException
- * @throws ConfigInvalidException
*/
public void load(Project.NameKey projectName, Repository db)
throws IOException, ConfigInvalidException {
@@ -151,8 +148,6 @@
* @param projectName the name of the project
* @param db repository to access.
* @param id revision to load.
- * @throws IOException
- * @throws ConfigInvalidException
*/
public void load(Project.NameKey projectName, Repository db, @Nullable ObjectId id)
throws IOException, ConfigInvalidException {
@@ -175,8 +170,6 @@
* @param projectName the name of the project
* @param walk open walk to access to access.
* @param id revision to load.
- * @throws IOException
- * @throws ConfigInvalidException
*/
public void load(Project.NameKey projectName, RevWalk walk, ObjectId id)
throws IOException, ConfigInvalidException {
@@ -461,12 +454,12 @@
}
protected Config readConfig(String fileName) throws IOException, ConfigInvalidException {
- return readConfig(fileName, null);
+ return readConfig(fileName, Optional.empty());
}
- protected Config readConfig(String fileName, Config baseConfig)
+ protected Config readConfig(String fileName, Optional<? extends Config> baseConfig)
throws IOException, ConfigInvalidException {
- Config rc = new Config(baseConfig);
+ Config rc = new Config(baseConfig.isPresent() ? baseConfig.get() : null);
String text = readUTF8(fileName);
if (!text.isEmpty()) {
try {
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index 5b26f61..488b008 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -40,8 +40,8 @@
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.ReceiveCommitsExecutor;
-import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.gerrit.server.git.MultiProgressMonitor;
+import com.google.gerrit.server.git.MultiProgressMonitor.TaskKind;
import com.google.gerrit.server.git.PermissionAwareRepositoryManager;
import com.google.gerrit.server.git.ProjectRunnable;
import com.google.gerrit.server.git.TransferConfig;
@@ -141,9 +141,8 @@
}
private static MultiProgressMonitor newMultiProgressMonitor(
- ExperimentFeatures experimentFeatures, MessageSender messageSender) {
- return new MultiProgressMonitor(
- experimentFeatures,
+ MultiProgressMonitor.Factory multiProgressMonitorFactory, MessageSender messageSender) {
+ return multiProgressMonitorFactory.create(
new OutputStream() {
@Override
public void write(int b) {
@@ -165,6 +164,7 @@
messageSender.flush();
}
},
+ TaskKind.RECEIVE_COMMITS,
"Processing changes");
}
@@ -222,7 +222,7 @@
}
}
- private final ExperimentFeatures experimentFeatures;
+ private final MultiProgressMonitor.Factory multiProgressMonitorFactory;
private final Metrics metrics;
private final ReceiveCommits receiveCommits;
private final PermissionBackend.ForProject perm;
@@ -240,7 +240,7 @@
@Inject
AsyncReceiveCommits(
- ExperimentFeatures experimentFeatures,
+ MultiProgressMonitor.Factory multiProgressMonitorFactory,
ReceiveCommits.Factory factory,
PermissionBackend permissionBackend,
Provider<InternalChangeQuery> queryProvider,
@@ -261,7 +261,7 @@
@Assisted Repository repo,
@Assisted @Nullable MessageSender messageSender)
throws PermissionBackendException {
- this.experimentFeatures = experimentFeatures;
+ this.multiProgressMonitorFactory = multiProgressMonitorFactory;
this.executor = executor;
this.scopePropagator = scopePropagator;
this.receiveConfig = receiveConfig;
@@ -386,7 +386,7 @@
}
String currentThreadName = Thread.currentThread().getName();
MultiProgressMonitor monitor =
- newMultiProgressMonitor(experimentFeatures, receiveCommits.getMessageSender());
+ newMultiProgressMonitor(multiProgressMonitorFactory, receiveCommits.getMessageSender());
Callable<ReceiveCommitsResult> callable =
() -> {
String oldName = Thread.currentThread().getName();
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 1e77cc4..c1cd30c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -102,7 +102,9 @@
import com.google.gerrit.extensions.validators.CommentValidationFailure;
import com.google.gerrit.extensions.validators.CommentValidator;
import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Counter3;
import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.CancellationMetrics;
import com.google.gerrit.server.ChangeUtil;
@@ -323,6 +325,7 @@
@Singleton
private static class Metrics {
private final Counter0 psRevisionMissing;
+ private final Counter3<String, String, String> pushCount;
@Inject
Metrics(MetricMaker metricMaker) {
@@ -330,6 +333,23 @@
metricMaker.newCounter(
"receivecommits/ps_revision_missing",
new Description("errors due to patch set revision missing"));
+ pushCount =
+ metricMaker.newCounter(
+ "receivecommits/push_count",
+ new Description("number of pushes"),
+ Field.ofString("kind", (metadataBuilder, fieldValue) -> {})
+ .description("The push kind (direct vs. magic).")
+ .build(),
+ Field.ofString(
+ "project",
+ (metadataBuilder, fieldValue) -> metadataBuilder.projectName(fieldValue))
+ .description("The name of the project for which the push is done.")
+ .build(),
+ Field.ofString("type", (metadataBuilder, fieldValue) -> {})
+ .description(
+ "The type of the update (CREATE, UPDATE, CREATE/UPDATE,"
+ + " UPDATE_NONFASTFORWARD, DELETE).")
+ .build());
}
}
@@ -627,7 +647,7 @@
ReceiveCommitsResult processCommands(
Collection<ReceiveCommand> commands, MultiProgressMonitor progress) throws StorageException {
checkState(!used, "Tried to re-use a ReceiveCommits objects that is single-use only");
- long start = System.nanoTime();
+ long start = TimeUtil.nowNanos();
parsePushOptions();
String clientProvidedDeadlineValue =
Iterables.getLast(pushOptions.get("deadline"), /* defaultValue= */ null);
@@ -637,10 +657,10 @@
tracePushOption.isPresent(),
tracePushOption.orElse(null),
(tagName, traceId) -> addMessage(tagName + ": " + traceId));
- TraceTimer traceTimer =
- newTimer("processCommands", Metadata.builder().resourceCount(commandCount));
PerformanceLogContext performanceLogContext =
- new PerformanceLogContext(config, performanceLoggers)) {
+ new PerformanceLogContext(config, performanceLoggers);
+ TraceTimer traceTimer =
+ newTimer("processCommands", Metadata.builder().resourceCount(commandCount))) {
RequestInfo requestInfo =
RequestInfo.builder(RequestInfo.RequestType.GIT_RECEIVE, user, traceContext)
.project(project.getNameKey())
@@ -727,6 +747,13 @@
return;
}
+ if (!magicCommands.isEmpty()) {
+ metrics.pushCount.increment("magic", project.getName(), getUpdateType(magicCommands));
+ }
+ if (!regularCommands.isEmpty()) {
+ metrics.pushCount.increment("direct", project.getName(), getUpdateType(regularCommands));
+ }
+
try {
if (!regularCommands.isEmpty()) {
handleRegularCommands(regularCommands, progress);
@@ -777,6 +804,15 @@
lazy(() -> commands.stream().map(ReceiveCommits::commandToString).collect(joining(","))));
}
+ private String getUpdateType(List<ReceiveCommand> commands) {
+ return commands.stream()
+ .map(ReceiveCommand::getType)
+ .map(ReceiveCommand.Type::name)
+ .distinct()
+ .sorted()
+ .collect(joining("/"));
+ }
+
private void sendErrorMessages() {
if (!errors.isEmpty()) {
logger.atFine().log("Handling error conditions: %s", errors.keySet());
@@ -1726,6 +1762,7 @@
}
@UsedAt(UsedAt.Project.GOOGLE)
+ @SuppressWarnings("unused") // unused in upstream, but used at Google
@Option(name = "--create-cod-token", usage = "create a token for consistency-on-demand")
private boolean createCodToken;
@@ -2882,8 +2919,6 @@
* </ul>
*
* @return whether the new commit is valid
- * @throws IOException
- * @throws PermissionBackendException
*/
boolean validateNewPatchSet() throws IOException, PermissionBackendException {
try (TraceTimer traceTimer = newTimer("validateNewPatchSet")) {
diff --git a/java/com/google/gerrit/server/git/receive/ReplaceOp.java b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
index b2a31b9..a9ef70e 100644
--- a/java/com/google/gerrit/server/git/receive/ReplaceOp.java
+++ b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
@@ -345,8 +345,11 @@
update.putReviewer(ctx.getAccountId(), REVIEWER);
}
- mailMessage = insertChangeMessage(update, ctx, reviewMessage);
+ // Approvals that are being set in the new patch-set during this operation are not available yet
+ // outside of the scope of this method. Only copied approvals are set here.
+ approvalsUtil.byPatchSet(ctx.getNotes(), newPatchSet).forEach(a -> update.putCopiedApproval(a));
+ mailMessage = insertChangeMessage(update, ctx, reviewMessage);
if (mergedByPushOp == null) {
resetChange(ctx);
} else {
diff --git a/java/com/google/gerrit/server/git/validators/OnSubmitValidationListener.java b/java/com/google/gerrit/server/git/validators/OnSubmitValidationListener.java
index 432dda3..98f2aa2 100644
--- a/java/com/google/gerrit/server/git/validators/OnSubmitValidationListener.java
+++ b/java/com/google/gerrit/server/git/validators/OnSubmitValidationListener.java
@@ -76,8 +76,8 @@
}
/**
- * @return a map from ref to commands covering all ref operations to be performed on this
- * repository as part of the ongoing submit operation.
+ * Returns a map from ref to commands covering all ref operations to be performed on this
+ * repository as part of the ongoing submit operation.
*/
public ImmutableMap<String, ReceiveCommand> getCommands() {
return commands;
diff --git a/java/com/google/gerrit/server/group/db/GroupDelta.java b/java/com/google/gerrit/server/group/db/GroupDelta.java
index 4ef2450..69cb936 100644
--- a/java/com/google/gerrit/server/group/db/GroupDelta.java
+++ b/java/com/google/gerrit/server/group/db/GroupDelta.java
@@ -121,19 +121,39 @@
@AutoValue.Builder
public abstract static class Builder {
- /** @see #getName() */
+ /**
+ * Defines the new name of the group
+ *
+ * <p>See {@link #getName}.
+ */
public abstract Builder setName(AccountGroup.NameKey name);
- /** @see #getDescription() */
+ /**
+ * Defines the new description of the group
+ *
+ * <p>See {@link #getDescription()}}
+ */
public abstract Builder setDescription(String description);
- /** @see #getOwnerGroupUUID() */
+ /**
+ * Defines the new owner of the group
+ *
+ * <p>See {@link #getOwnerGroupUUID()}
+ */
public abstract Builder setOwnerGroupUUID(AccountGroup.UUID ownerGroupUUID);
- /** @see #getVisibleToAll() */
+ /**
+ * Defines the new state of the 'visibleToAll' flag of the group
+ *
+ * <p>See {@link #getVisibleToAll()}
+ */
public abstract Builder setVisibleToAll(boolean visibleToAll);
- /** @see #getMemberModification() */
+ /**
+ * Set {@link MemberModification} for the prospective {@link GroupDelta}
+ *
+ * <p>See {@link #getMemberModification()}
+ */
public abstract Builder setMemberModification(MemberModification memberModification);
/**
@@ -146,7 +166,11 @@
*/
public abstract MemberModification getMemberModification();
- /** @see #getSubgroupModification() */
+ /**
+ * Set {@link SubgroupModification} for the prospective {@link GroupDelta}
+ *
+ * <p>See {@link #getSubgroupModification()}
+ */
public abstract Builder setSubgroupModification(SubgroupModification subgroupModification);
/**
@@ -159,7 +183,12 @@
*/
public abstract SubgroupModification getSubgroupModification();
- /** @see #getUpdatedOn() */
+ /**
+ * Defines the {@code Timestamp} to be used for the NoteDb commits of the update. If not
+ * specified, the current {@code Timestamp} when creating the commit will be used.
+ *
+ * <p>See {@link #getUpdatedOn()}
+ */
public abstract Builder setUpdatedOn(Timestamp timestamp);
public abstract GroupDelta build();
diff --git a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
index 01ee811..24bcaf0 100644
--- a/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
+++ b/java/com/google/gerrit/server/group/db/GroupsNoteDbConsistencyChecker.java
@@ -22,6 +22,7 @@
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
+import com.google.errorprone.annotations.FormatMethod;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.entities.GroupReference;
@@ -138,8 +139,7 @@
Optional<Ref> maybeRef =
refs.stream().filter(r -> r.getName().equals(RefNames.REFS_GROUPNAMES)).findFirst();
if (!maybeRef.isPresent()) {
- String msg = String.format("ref %s does not exist", RefNames.REFS_GROUPNAMES);
- result.problems.add(error(msg));
+ result.problems.add(error("ref %s does not exist", RefNames.REFS_GROUPNAMES));
return;
}
Ref ref = maybeRef.get();
@@ -280,6 +280,7 @@
}
}
+ @FormatMethod
public static void logConsistencyProblemAsWarning(String fmt, Object... args) {
logConsistencyProblem(warning(fmt, args));
}
diff --git a/java/com/google/gerrit/server/group/db/InternalGroupCreation.java b/java/com/google/gerrit/server/group/db/InternalGroupCreation.java
index f4bf6e6..291c354 100644
--- a/java/com/google/gerrit/server/group/db/InternalGroupCreation.java
+++ b/java/com/google/gerrit/server/group/db/InternalGroupCreation.java
@@ -26,13 +26,13 @@
@AutoValue
public abstract class InternalGroupCreation {
- /** Defines the numeric ID the group should have. */
+ /** Defines the numeric ID the group should have */
public abstract AccountGroup.Id getId();
- /** Defines the name the group should have. */
+ /** Defines the name the group should have */
public abstract AccountGroup.NameKey getNameKey();
- /** Defines the UUID the group should have. */
+ /** Defines the UUID the group should have */
public abstract AccountGroup.UUID getGroupUUID();
public static Builder builder() {
@@ -41,13 +41,13 @@
@AutoValue.Builder
public abstract static class Builder {
- /** @see #getId() */
+ /** Defines the name the group should have */
public abstract InternalGroupCreation.Builder setId(AccountGroup.Id id);
- /** @see #getNameKey() */
+ /** Defines the name the group should have */
public abstract InternalGroupCreation.Builder setNameKey(AccountGroup.NameKey name);
- /** @see #getGroupUUID() */
+ /** Defines the UUID the group should have */
public abstract InternalGroupCreation.Builder setGroupUUID(AccountGroup.UUID groupUuid);
public abstract InternalGroupCreation build();
diff --git a/java/com/google/gerrit/server/index/IndexModule.java b/java/com/google/gerrit/server/index/IndexModule.java
index 6db00f5..e580f50 100644
--- a/java/com/google/gerrit/server/index/IndexModule.java
+++ b/java/com/google/gerrit/server/index/IndexModule.java
@@ -33,6 +33,7 @@
import com.google.gerrit.index.project.ProjectSchemaDefinitions;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.git.MultiProgressMonitor;
import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.account.AccountIndexDefinition;
@@ -110,6 +111,7 @@
@Override
protected void configure() {
+ factory(MultiProgressMonitor.Factory.class);
bind(AccountIndexRewriter.class);
bind(AccountIndexCollection.class);
diff --git a/java/com/google/gerrit/server/index/VersionManager.java b/java/com/google/gerrit/server/index/VersionManager.java
index 56ce604..cdb69c6 100644
--- a/java/com/google/gerrit/server/index/VersionManager.java
+++ b/java/com/google/gerrit/server/index/VersionManager.java
@@ -107,7 +107,6 @@
* @param name index name
* @param force start re-index
* @return true if started, otherwise false.
- * @throws ReindexerAlreadyRunningException
*/
public synchronized boolean startReindexer(String name, boolean force)
throws ReindexerAlreadyRunningException {
@@ -125,7 +124,6 @@
*
* @param name index name
* @return true if index was activated, otherwise false.
- * @throws ReindexerAlreadyRunningException
*/
public synchronized boolean activateLatestIndex(String name)
throws ReindexerAlreadyRunningException {
diff --git a/java/com/google/gerrit/server/index/change/AllChangesIndexer.java b/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
index ab90e32..1b51703 100644
--- a/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
+++ b/java/com/google/gerrit/server/index/change/AllChangesIndexer.java
@@ -30,10 +30,10 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.index.SiteIndexer;
-import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MultiProgressMonitor;
import com.google.gerrit.server.git.MultiProgressMonitor.Task;
+import com.google.gerrit.server.git.MultiProgressMonitor.TaskKind;
import com.google.gerrit.server.index.IndexExecutor;
import com.google.gerrit.server.index.OnlineReindexMode;
import com.google.gerrit.server.notedb.ChangeNotes;
@@ -63,7 +63,7 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final int PROJECT_SLICE_MAX_REFS = 1000;
- private final ExperimentFeatures experimentFeatures;
+ private final MultiProgressMonitor.Factory multiProgressMonitorFactory;
private final ChangeData.Factory changeDataFactory;
private final GitRepositoryManager repoManager;
private final ListeningExecutorService executor;
@@ -73,14 +73,14 @@
@Inject
AllChangesIndexer(
- ExperimentFeatures experimentFeatures,
+ MultiProgressMonitor.Factory multiProgressMonitorFactory,
ChangeData.Factory changeDataFactory,
GitRepositoryManager repoManager,
@IndexExecutor(BATCH) ListeningExecutorService executor,
ChangeIndexer.Factory indexerFactory,
ChangeNotes.Factory notesFactory,
ProjectCache projectCache) {
- this.experimentFeatures = experimentFeatures;
+ this.multiProgressMonitorFactory = multiProgressMonitorFactory;
this.changeDataFactory = changeDataFactory;
this.repoManager = repoManager;
this.executor = executor;
@@ -185,7 +185,7 @@
private SiteIndexer.Result indexAll(ChangeIndex index, List<ProjectSlice> projectSlices) {
Stopwatch sw = Stopwatch.createStarted();
MultiProgressMonitor mpm =
- new MultiProgressMonitor(experimentFeatures, progressOut, "Reindexing changes");
+ multiProgressMonitorFactory.create(progressOut, TaskKind.INDEXING, "Reindexing changes");
Task projTask = mpm.beginSubTask("project-slices", projectSlices.size());
checkState(totalWork >= 0);
Task doneTask = mpm.beginSubTask(null, totalWork);
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index 5caceef..bfe1ee1 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -342,6 +342,11 @@
integer(ChangeQueryBuilder.FIELD_ATTENTION_SET_USERS)
.buildRepeatable(ChangeField::getAttentionSetUserIds);
+ /** Number of changes that contain attention set. */
+ public static final FieldDef<ChangeData, Integer> ATTENTION_SET_USERS_COUNT =
+ intRange(ChangeQueryBuilder.FIELD_ATTENTION_SET_USERS_COUNT)
+ .build(cd -> additionsOnly(cd.attentionSet()).size());
+
/**
* The full attention set data including timestamp, reason and possible future fields.
*
@@ -598,9 +603,9 @@
/** List of labels on the current patch set including change owner votes. */
public static final FieldDef<ChangeData, Iterable<String>> LABEL =
- exact("label2").buildRepeatable(cd -> getLabels(cd, true));
+ exact("label2").buildRepeatable(cd -> getLabels(cd));
- private static Iterable<String> getLabels(ChangeData cd, boolean owners) {
+ private static Iterable<String> getLabels(ChangeData cd) {
Set<String> allApprovals = new HashSet<>();
Set<String> distinctApprovals = new HashSet<>();
for (PatchSetApproval a : cd.currentApprovals()) {
@@ -608,12 +613,19 @@
allApprovals.add(formatLabel(a.label(), a.value(), a.accountId()));
Optional<LabelType> labelType = cd.getLabelTypes().byLabel(a.labelId());
allApprovals.addAll(getMaxMinAnyLabels(a.label(), a.value(), labelType, a.accountId()));
- if (owners && cd.change().getOwner().equals(a.accountId())) {
+ if (cd.change().getOwner().equals(a.accountId())) {
allApprovals.add(formatLabel(a.label(), a.value(), ChangeQueryBuilder.OWNER_ACCOUNT_ID));
allApprovals.addAll(
getMaxMinAnyLabels(
a.label(), a.value(), labelType, ChangeQueryBuilder.OWNER_ACCOUNT_ID));
}
+ if (!cd.currentPatchSet().uploader().equals(a.accountId())) {
+ allApprovals.add(
+ formatLabel(a.label(), a.value(), ChangeQueryBuilder.NON_UPLOADER_ACCOUNT_ID));
+ allApprovals.addAll(
+ getMaxMinAnyLabels(
+ a.label(), a.value(), labelType, ChangeQueryBuilder.NON_UPLOADER_ACCOUNT_ID));
+ }
distinctApprovals.add(formatLabel(a.label(), a.value()));
distinctApprovals.addAll(getMaxMinAnyLabels(a.label(), a.value(), labelType, null));
}
@@ -735,6 +747,8 @@
private static String formatAccount(Account.Id accountId) {
if (ChangeQueryBuilder.OWNER_ACCOUNT_ID.equals(accountId)) {
return ChangeQueryBuilder.ARG_ID_OWNER;
+ } else if (ChangeQueryBuilder.NON_UPLOADER_ACCOUNT_ID.equals(accountId)) {
+ return ChangeQueryBuilder.ARG_ID_NON_UPLOADER;
}
return Integer.toString(accountId.get());
}
@@ -796,6 +810,12 @@
return m ? "1" : "0";
});
+ /** Whether the change is a cherry pick of another change. */
+ public static final FieldDef<ChangeData, String> CHERRY_PICK =
+ exact(ChangeQueryBuilder.FIELD_CHERRYPICK)
+ .stored()
+ .build(cd -> cd.change().getCherryPickOf() != null ? "1" : "0");
+
/** The number of inserted lines in this change. */
public static final FieldDef<ChangeData, Integer> ADDED =
intRange(ChangeQueryBuilder.FIELD_ADDED)
@@ -919,6 +939,19 @@
public static final SubmitRuleOptions SUBMIT_RULE_OPTIONS_STRICT =
SubmitRuleOptions.builder().build();
+ /** All submit rules results in the form of "$ruleName,$status". */
+ public static final FieldDef<ChangeData, Iterable<String>> SUBMIT_RULE_RESULT =
+ exact("submit_rule_result")
+ .buildRepeatable(
+ cd -> {
+ List<String> result = new ArrayList<>();
+ List<SubmitRecord> submitRecords = cd.submitRecords(SUBMIT_RULE_OPTIONS_STRICT);
+ for (SubmitRecord record : submitRecords) {
+ result.add(record.ruleName + "=" + record.status.name());
+ }
+ return result;
+ });
+
/**
* JSON type for storing SubmitRecords.
*
@@ -938,12 +971,14 @@
@Deprecated Map<String, String> data;
}
+ String ruleName;
SubmitRecord.Status status;
List<StoredLabel> labels;
List<StoredRequirement> requirements;
String errorMessage;
public StoredSubmitRecord(SubmitRecord rec) {
+ this.ruleName = rec.ruleName;
this.status = rec.status;
this.errorMessage = rec.errorMessage;
if (rec.labels != null) {
@@ -975,6 +1010,7 @@
public SubmitRecord toSubmitRecord() {
SubmitRecord rec = new SubmitRecord();
+ rec.ruleName = ruleName;
rec.status = status;
rec.errorMessage = errorMessage;
if (labels != null) {
diff --git a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index bee0c35..30ab6e6a 100644
--- a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -154,10 +154,34 @@
@Deprecated static final Schema<ChangeData> V64 = schema(V63, false);
/** Added new field for submit requirements. */
+ @Deprecated
static final Schema<ChangeData> V65 =
new Schema.Builder<ChangeData>().add(V64).add(ChangeField.STORED_SUBMIT_REQUIREMENTS).build();
/**
+ * The computation of {@link ChangeField#LABEL} has changed: We added the non_uploader arg to the
+ * label field.
+ */
+ @Deprecated static final Schema<ChangeData> V66 = schema(V65, false);
+
+ /** Updated submit records: store the rule name that created the submit record. */
+ @Deprecated static final Schema<ChangeData> V67 = schema(V66, false);
+
+ /** Added new field {@link ChangeField#SUBMIT_RULE_RESULT}. */
+ @Deprecated
+ static final Schema<ChangeData> V68 =
+ new Schema.Builder<ChangeData>().add(V67).add(ChangeField.SUBMIT_RULE_RESULT).build();
+
+ /** Added new field {@link ChangeField#CHERRY_PICK}. */
+ @Deprecated
+ static final Schema<ChangeData> V69 =
+ new Schema.Builder<ChangeData>().add(V68).add(ChangeField.CHERRY_PICK).build();
+
+ /** Added new field {@link ChangeField#ATTENTION_SET_USERS_COUNT}. */
+ static final Schema<ChangeData> V70 =
+ new Schema.Builder<ChangeData>().add(V69).add(ChangeField.ATTENTION_SET_USERS_COUNT).build();
+
+ /**
* Name of the change index to be used when contacting index backends or loading configurations.
*/
public static final String NAME = "changes";
diff --git a/java/com/google/gerrit/server/ioutil/HostPlatform.java b/java/com/google/gerrit/server/ioutil/HostPlatform.java
index 39e9c07..e27d17c 100644
--- a/java/com/google/gerrit/server/ioutil/HostPlatform.java
+++ b/java/com/google/gerrit/server/ioutil/HostPlatform.java
@@ -21,7 +21,7 @@
private static final boolean win32 = compute("windows");
private static final boolean mac = compute("mac");
- /** @return true if this JVM is running on a Windows platform. */
+ /** Returns true if this JVM is running on a Windows platform. */
public static boolean isWin32() {
return win32;
}
diff --git a/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java b/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
index 015887b..a58d9ae 100644
--- a/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
+++ b/java/com/google/gerrit/server/ioutil/LimitedByteArrayOutputStream.java
@@ -57,7 +57,7 @@
buffer.write(b, off, len);
}
- /** @return a newly allocated byte array with contents of the buffer. */
+ /** Returns a newly allocated byte array with contents of the buffer. */
public byte[] toByteArray() {
return buffer.toByteArray();
}
diff --git a/java/com/google/gerrit/server/logging/CallerFinder.java b/java/com/google/gerrit/server/logging/CallerFinder.java
index bd7e608..4cb4b7f 100644
--- a/java/com/google/gerrit/server/logging/CallerFinder.java
+++ b/java/com/google/gerrit/server/logging/CallerFinder.java
@@ -41,7 +41,7 @@
*
* <p>E.g. the stacktrace could look like this:
*
- * <pre>
+ * <pre>{@code
* GroupQueryProcessor(QueryProcessor<T>).query(List<String>, List<Predicate<T>>) line: 216
* GroupQueryProcessor(QueryProcessor<T>).query(List<Predicate<T>>) line: 188
* GroupQueryProcessor(QueryProcessor<T>).query(Predicate<T>) line: 171
@@ -52,7 +52,7 @@
* GroupCacheImpl$ByNameLoader.load(Object) line: 1
* LocalCache$LoadingValueReference<K,V>.loadFuture(K, CacheLoader<? super K,V>) line: 3527
* ...
- * </pre>
+ * }</pre>
*
* <p>The first interesting caller is {@code GroupCacheImpl$ByNameLoader.load(String) line: 166}. To
* find this caller from the stacktrace we could specify {@link
diff --git a/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java b/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java
index 3c4c563..1bba018 100644
--- a/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java
+++ b/java/com/google/gerrit/server/logging/LoggingContextAwareRunnable.java
@@ -28,24 +28,24 @@
*
* <p>Example:
*
- * <pre>
- * try (TraceContext traceContext = TraceContext.newTrace(true, ...)) {
- * executor
- * .submit(new LoggingContextAwareRunnable(
- * () -> {
- * // Tracing is enabled since the runnable is created within the TraceContext.
- * // Tracing is even enabled if the executor runs the runnable only after the
- * // TraceContext was closed.
+ * <pre>{@code
+ * try (TraceContext traceContext = TraceContext.newTrace(true, ...)) {
+ * executor
+ * .submit(new LoggingContextAwareRunnable(
+ * () -> {
+ * // Tracing is enabled since the runnable is created within the TraceContext.
+ * // Tracing is even enabled if the executor runs the runnable only after the
+ * // TraceContext was closed.
*
- * // The tag "foo=bar" is not set, since it was added to the logging context only
- * // after this runnable was created.
+ * // The tag "foo=bar" is not set, since it was added to the logging context only
+ * // after this runnable was created.
*
- * // do stuff
- * }))
- * .get();
- * traceContext.addTag("foo", "bar");
- * }
- * </pre>
+ * // do stuff
+ * }))
+ * .get();
+ * traceContext.addTag("foo", "bar");
+ * }
+ * }</pre>
*
* @see LoggingContextAwareCallable
*/
diff --git a/java/com/google/gerrit/server/logging/TraceContext.java b/java/com/google/gerrit/server/logging/TraceContext.java
index 681dfbc..487e0af 100644
--- a/java/com/google/gerrit/server/logging/TraceContext.java
+++ b/java/com/google/gerrit/server/logging/TraceContext.java
@@ -268,15 +268,23 @@
return this;
}
- public boolean isTracing() {
+ public static boolean isTracing() {
return LoggingContext.getInstance().isLoggingForced();
}
- public Optional<String> getTraceId() {
+ public static Optional<String> getTraceId() {
return LoggingContext.getInstance().getTagsAsMap().get(RequestId.Type.TRACE_ID.name()).stream()
.findFirst();
}
+ public static Optional<String> getPluginTag() {
+ return getTag(PLUGIN_TAG);
+ }
+
+ public static Optional<String> getTag(String tagName) {
+ return LoggingContext.getInstance().getTagsAsMap().get(tagName).stream().findFirst();
+ }
+
public TraceContext enableAclLogging() {
if (stopAclLoggingOnClose) {
return this;
@@ -286,11 +294,7 @@
return this;
}
- public boolean isAclLoggingEnabled() {
- return LoggingContext.getInstance().isAclLogging();
- }
-
- public ImmutableList<String> getAclLogRecords() {
+ public static ImmutableList<String> getAclLogRecords() {
return LoggingContext.getInstance().getAclLogRecords();
}
diff --git a/java/com/google/gerrit/server/mail/EmailTokenVerifier.java b/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
index 2ff5fc3..ead4c06 100644
--- a/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
+++ b/java/com/google/gerrit/server/mail/EmailTokenVerifier.java
@@ -56,10 +56,13 @@
class ParsedToken {
private final Account.Id accountId;
private final String emailAddress;
+ private final AuthRequest.Factory authRequestFactory;
- public ParsedToken(Account.Id accountId, String emailAddress) {
+ public ParsedToken(
+ Account.Id accountId, String emailAddress, AuthRequest.Factory authRequestFactory) {
this.accountId = accountId;
this.emailAddress = emailAddress;
+ this.authRequestFactory = authRequestFactory;
}
public Account.Id getAccountId() {
@@ -71,7 +74,7 @@
}
public AuthRequest toAuthRequest() {
- return AuthRequest.forEmail(getEmailAddress());
+ return authRequestFactory.createForEmail(getEmailAddress());
}
@Override
diff --git a/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java b/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
index 77be665..bdfaf6d 100644
--- a/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
+++ b/java/com/google/gerrit/server/mail/SignedTokenEmailTokenVerifier.java
@@ -19,6 +19,7 @@
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.mail.send.RegisterNewEmailSender;
import com.google.inject.AbstractModule;
@@ -31,6 +32,7 @@
@Singleton
public class SignedTokenEmailTokenVerifier implements EmailTokenVerifier {
private final SignedToken emailRegistrationToken;
+ private final AuthRequest.Factory authRequestFactory;
public static class Module extends AbstractModule {
@Override
@@ -40,8 +42,9 @@
}
@Inject
- SignedTokenEmailTokenVerifier(AuthConfig config) {
+ SignedTokenEmailTokenVerifier(AuthConfig config, AuthRequest.Factory authRequestFactory) {
emailRegistrationToken = config.getEmailRegistrationToken();
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -77,7 +80,7 @@
}
Account.Id id = Account.Id.tryParse(matcher.group(1)).orElseThrow(InvalidTokenException::new);
String newEmail = matcher.group(2);
- return new ParsedToken(id, newEmail);
+ return new ParsedToken(id, newEmail, authRequestFactory);
}
private void checkEmailRegistrationToken() {
diff --git a/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index d805e39..e98647d 100644
--- a/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.mail.receive;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
@@ -91,7 +92,7 @@
private static final ImmutableMap<MailComment.CommentType, CommentForValidation.CommentType>
MAIL_COMMENT_TYPE_TO_VALIDATION_TYPE =
ImmutableMap.of(
- MailComment.CommentType.CHANGE_MESSAGE,
+ MailComment.CommentType.PATCHSET_LEVEL,
CommentForValidation.CommentType.CHANGE_MESSAGE,
MailComment.CommentType.FILE_COMMENT, CommentForValidation.CommentType.FILE_COMMENT,
MailComment.CommentType.INLINE_COMMENT,
@@ -342,9 +343,6 @@
changeMessagesUtil.setChangeMessage(ctx.getUpdate(psId), generateChangeMessage(), tag);
comments = new ArrayList<>();
for (MailComment c : parsedComments) {
- if (c.getType() == MailComment.CommentType.CHANGE_MESSAGE) {
- continue;
- }
comments.add(
persistentCommentFromMailComment(ctx, c, targetPatchSetForComment(ctx, c, patchSet)));
}
@@ -359,7 +357,7 @@
@Override
public void postUpdate(PostUpdateContext ctx) throws Exception {
String patchSetComment = null;
- if (parsedComments.get(0).getType() == MailComment.CommentType.CHANGE_MESSAGE) {
+ if (parsedComments.get(0).getType() == MailComment.CommentType.PATCHSET_LEVEL) {
patchSetComment = parsedComments.get(0).getMessage();
}
// Send email notifications
@@ -396,15 +394,7 @@
private String generateChangeMessage() {
String changeMsg = "Patch Set " + psId.get() + ":";
- if (parsedComments.get(0).getType() == MailComment.CommentType.CHANGE_MESSAGE) {
- // Add a blank line after Patch Set to follow the default format
- if (parsedComments.size() > 1) {
- changeMsg += "\n\n" + numComments(parsedComments.size() - 1);
- }
- changeMsg += "\n\n" + parsedComments.get(0).getMessage();
- } else {
- changeMsg += "\n\n" + numComments(parsedComments.size());
- }
+ changeMsg += "\n\n" + numComments(parsedComments.size());
return changeMsg;
}
@@ -424,7 +414,11 @@
// The patch set that this comment is based on is different if this
// comment was sent in reply to a comment on a previous patch set.
Side side;
- if (mailComment.getInReplyTo() != null) {
+ if (mailComment.getType() == MailComment.CommentType.PATCHSET_LEVEL) {
+ fileName = PATCHSET_LEVEL;
+ // Patchset comments do not have side.
+ side = Side.REVISION;
+ } else if (mailComment.getInReplyTo() != null) {
fileName = mailComment.getInReplyTo().key.filename;
side = Side.fromShort(mailComment.getInReplyTo().side);
} else {
diff --git a/java/com/google/gerrit/server/mail/receive/MailReceiver.java b/java/com/google/gerrit/server/mail/receive/MailReceiver.java
index dc99b46..e383207 100644
--- a/java/com/google/gerrit/server/mail/receive/MailReceiver.java
+++ b/java/com/google/gerrit/server/mail/receive/MailReceiver.java
@@ -110,8 +110,6 @@
* requestDeletion will enqueue an email for deletion and delete it the next time we connect to
* the email server. This does not guarantee deletion as the Gerrit instance might fail before we
* connect to the email server.
- *
- * @param messageId
*/
public void requestDeletion(String messageId) {
pendingDeletion.add(messageId);
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index 48ab397..1a2e150 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -41,11 +41,10 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.mail.send.ProjectWatch.Watchers;
import com.google.gerrit.server.notedb.ReviewerStateInternal;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.FilePathAdapter;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -66,6 +65,7 @@
import org.apache.james.mime4j.dom.field.FieldName;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.TemporaryBuffer;
@@ -269,17 +269,23 @@
if (patchSet != null) {
detail.append("---\n");
- PatchList patchList = getPatchList();
- for (PatchListEntry p : patchList.getPatches()) {
- if (Patch.isMagic(p.getNewName())) {
+ Map<String, FileDiffOutput> modifiedFiles = listModifiedFiles();
+ for (FileDiffOutput fileDiff : modifiedFiles.values()) {
+ if (fileDiff.newPath().isPresent() && Patch.isMagic(fileDiff.newPath().get())) {
continue;
}
detail
- .append(p.getChangeType().getCode())
+ .append(fileDiff.changeType().getCode())
.append(" ")
- .append(p.getNewName())
+ .append(
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType()))
.append("\n");
}
+ Integer insertions =
+ modifiedFiles.values().stream().map(FileDiffOutput::insertions).reduce(0, Integer::sum);
+ Integer deletions =
+ modifiedFiles.values().stream().map(FileDiffOutput::deletions).reduce(0, Integer::sum);
detail.append(
MessageFormat.format(
"" //
@@ -287,9 +293,9 @@
+ "{1,choice,0#0 insertions|1#1 insertion|1<{1} insertions}(+), " //
+ "{2,choice,0#0 deletions|1#1 deletion|1<{2} deletions}(-)" //
+ "\n",
- patchList.getPatches().size() - 1, //
- patchList.getInsertions(), //
- patchList.getDeletions()));
+ modifiedFiles.size() - 1, //
+ insertions, //
+ deletions));
detail.append("\n");
}
return detail.toString();
@@ -300,7 +306,8 @@
}
/** Get the patch list corresponding to patch set patchSetId of this change. */
- protected PatchList getPatchList(int patchSetId) throws PatchListNotAvailableException {
+ protected Map<String, FileDiffOutput> listModifiedFiles(int patchSetId)
+ throws DiffNotAvailableException {
PatchSet ps;
if (patchSetId == patchSet.number()) {
ps = patchSet;
@@ -308,18 +315,20 @@
try {
ps = args.patchSetUtil.get(changeData.notes(), PatchSet.id(change.getId(), patchSetId));
} catch (StorageException e) {
- throw new PatchListNotAvailableException("Failed to get patchSet", e);
+ throw new DiffNotAvailableException("Failed to get patchSet", e);
}
}
- return args.patchListCache.get(change, ps);
+ return args.diffOperations.listModifiedFilesAgainstParent(
+ change.getProject(), ps.commitId(), /* parentNum= */ 0);
}
/** Get the patch list corresponding to this patch set. */
- protected PatchList getPatchList() throws PatchListNotAvailableException {
+ protected Map<String, FileDiffOutput> listModifiedFiles() throws DiffNotAvailableException {
if (patchSet != null) {
- return args.patchListCache.get(change, patchSet);
+ return args.diffOperations.listModifiedFilesAgainstParent(
+ change.getProject(), patchSet.commitId(), /* parentNum= */ 0);
}
- throw new PatchListNotAvailableException("no patchSet specified");
+ throw new DiffNotAvailableException("no patchSet specified");
}
/** Get the project entity the change is in; null if its been deleted. */
@@ -566,18 +575,15 @@
/** Show patch set as unified difference. */
public String getUnifiedDiff() {
- PatchList patchList;
+ Map<String, FileDiffOutput> modifiedFiles;
try {
- patchList = getPatchList();
- if (patchList.getOldId() == null) {
+ modifiedFiles = listModifiedFiles();
+ if (modifiedFiles.isEmpty()) {
// Octopus merges are not well supported for diff output by Gerrit.
// Currently these always have a null oldId in the PatchList.
return "[Octopus merge; cannot be formatted as a diff.]\n";
}
- } catch (PatchListObjectTooLargeException e) {
- logger.atWarning().log("Cannot format patch %s", e.getMessage());
- return "";
- } catch (PatchListNotAvailableException e) {
+ } catch (DiffNotAvailableException e) {
logger.atSevere().withCause(e).log("Cannot format patch");
return "";
}
@@ -587,9 +593,11 @@
try (DiffFormatter fmt = new DiffFormatter(buf)) {
try (Repository git = args.server.openRepository(change.getProject())) {
try {
+ ObjectId oldId = modifiedFiles.values().iterator().next().oldCommitId();
+ ObjectId newId = modifiedFiles.values().iterator().next().newCommitId();
fmt.setRepository(git);
fmt.setDetectRenames(true);
- fmt.format(patchList.getOldId(), patchList.getNewId());
+ fmt.format(oldId, newId);
return RawParseUtils.decode(buf.toByteArray());
} catch (IOException e) {
if (JGitText.get().inMemoryBufferLimitExceeded.equals(e.getMessage())) {
diff --git a/java/com/google/gerrit/server/mail/send/CommentSender.java b/java/com/google/gerrit/server/mail/send/CommentSender.java
index ac6c2f3..5a7352a 100644
--- a/java/com/google/gerrit/server/mail/send/CommentSender.java
+++ b/java/com/google/gerrit/server/mail/send/CommentSender.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.mail.send;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
@@ -36,10 +37,9 @@
import com.google.gerrit.server.CommentsUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.mail.receive.Protocol;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.PatchFile;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
-import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.util.LabelVote;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -72,23 +72,23 @@
public PatchFile fileData;
public List<Comment> comments = new ArrayList<>();
- /** @return a web link to a comment for a change. */
+ /** Returns a web link to a comment for a change. */
public String getCommentLink(String uuid) {
return args.urlFormatter.get().getInlineCommentView(change, uuid).orElse(null);
}
- /** @return a web link to the comment tab view of a change. */
+ /** Returns a web link to the comment tab view of a change. */
public String getCommentsTabLink() {
return args.urlFormatter.get().getCommentsTabView(change).orElse(null);
}
- /** @return a web link to the findings tab view of a change. */
+ /** Returns a web link to the findings tab view of a change. */
public String getFindingsTabLink() {
return args.urlFormatter.get().getFindingsTabView(change).orElse(null);
}
/**
- * @return A title for the group, i.e. "Commit Message", "Merge List", or "File [[filename]]".
+ * Returns a title for the group, i.e. "Commit Message", "Merge List", or "File [[filename]]".
*/
public String getTitle() {
if (Patch.COMMIT_MSG.equals(filename)) {
@@ -181,8 +181,8 @@
}
/**
- * @return a list of FileCommentGroup objects representing the inline comments grouped by the
- * file.
+ * Returns a list of FileCommentGroup objects representing the inline comments grouped by the
+ * file.
*/
private List<CommentSender.FileCommentGroup> getGroupedInlineComments(Repository repo) {
List<CommentSender.FileCommentGroup> groups = new ArrayList<>();
@@ -198,30 +198,30 @@
currentGroup = new FileCommentGroup();
currentGroup.filename = c.key.filename;
currentGroup.patchSetId = c.key.patchSetId;
- // Get the patch list:
- PatchList patchList = null;
+ // Get the modified files:
+ Map<String, FileDiffOutput> modifiedFiles = null;
try {
- patchList = getPatchList(c.key.patchSetId);
- } catch (PatchListObjectTooLargeException e) {
- logger.atWarning().log("Failed to get patch list: %s", e.getMessage());
- } catch (PatchListNotAvailableException e) {
- logger.atSevere().withCause(e).log("Failed to get patch list");
+ modifiedFiles = listModifiedFiles(c.key.patchSetId);
+ } catch (DiffNotAvailableException e) {
+ logger.atSevere().withCause(e).log("Failed to get modified files");
}
groups.add(currentGroup);
- if (patchList != null) {
+ if (modifiedFiles != null && !modifiedFiles.isEmpty()) {
try {
- currentGroup.fileData = new PatchFile(repo, patchList, c.key.filename);
+ currentGroup.fileData = new PatchFile(repo, modifiedFiles, c.key.filename);
} catch (IOException e) {
logger.atWarning().withCause(e).log(
"Cannot load %s from %s in %s",
- c.key.filename, patchList.getNewId().name(), projectState.getName());
+ c.key.filename,
+ modifiedFiles.values().iterator().next().newCommitId().name(),
+ projectState.getName());
currentGroup.fileData = null;
}
}
}
- if (currentGroup.fileData != null) {
+ if (currentGroup.filename.equals(PATCHSET_LEVEL) || currentGroup.fileData != null) {
currentGroup.comments.add(c);
}
}
@@ -268,7 +268,7 @@
}
/**
- * @return the lines of file content in fileData that are encompassed by range on the given side.
+ * Returns the lines of file content in fileData that are encompassed by range on the given side.
*/
private List<String> getLinesByRange(Comment.Range range, PatchFile fileData, short side) {
List<String> lines = new ArrayList<>();
@@ -331,9 +331,9 @@
}
/**
- * @return a shortened version of the given comment's message. Will be shortened to 100 characters
- * or the first line, or following the last period within the first 100 characters, whichever
- * is shorter. If the message is shortened, an ellipsis is appended.
+ * Returns a shortened version of the given comment's message. Will be shortened to 100 characters
+ * or the first line, or following the last period within the first 100 characters, whichever is
+ * shorter. If the message is shortened, an ellipsis is appended.
*/
protected static String getShortenedCommentMessage(String message) {
int threshold = 100;
@@ -369,8 +369,8 @@
}
/**
- * @return grouped inline comment data mapped to data structures that are suitable for passing
- * into Soy.
+ * Returns grouped inline comment data mapped to data structures that are suitable for passing
+ * into Soy.
*/
private List<Map<String, Object>> getCommentGroupsTemplateData(Repository repo) {
List<Map<String, Object>> commentGroups = new ArrayList<>();
@@ -383,7 +383,9 @@
List<Map<String, Object>> commentsList = new ArrayList<>();
for (Comment comment : group.comments) {
Map<String, Object> commentData = new HashMap<>();
- commentData.put("lines", getLinesOfComment(comment, group.fileData));
+ if (group.fileData != null) {
+ commentData.put("lines", getLinesOfComment(comment, group.fileData));
+ }
commentData.put("message", comment.message.trim());
List<CommentFormatter.Block> blocks = CommentFormatter.parse(comment.message);
commentData.put("messageBlocks", commentBlocksToSoyData(blocks));
diff --git a/java/com/google/gerrit/server/mail/send/EmailArguments.java b/java/com/google/gerrit/server/mail/send/EmailArguments.java
index 258c9af..96effc1 100644
--- a/java/com/google/gerrit/server/mail/send/EmailArguments.java
+++ b/java/com/google/gerrit/server/mail/send/EmailArguments.java
@@ -35,7 +35,7 @@
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mail.EmailSettings;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectCache;
@@ -43,6 +43,7 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.ssh.SshAdvertisedAddresses;
+import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.validators.OutgoingEmailValidationListener;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -71,7 +72,7 @@
final PermissionBackend permissionBackend;
final GroupBackend groupBackend;
final AccountCache accountCache;
- final PatchListCache patchListCache;
+ final DiffOperations diffOperations;
final PatchSetUtil patchSetUtil;
final ApprovalsUtil approvalsUtil;
final Provider<FromAddressGenerator> fromAddressGenerator;
@@ -86,7 +87,6 @@
final AllProjectsName allProjectsName;
final List<String> sshAddresses;
final SitePaths site;
-
final Provider<ChangeQueryBuilder> queryBuilder;
final ChangeData.Factory changeDataFactory;
final Provider<SoySauce> soySauce;
@@ -97,6 +97,7 @@
final boolean addInstanceNameInSubject;
final Provider<String> instanceNameProvider;
final Provider<CurrentUser> currentUserProvider;
+ final RetryHelper retryHelper;
@Inject
EmailArguments(
@@ -105,7 +106,7 @@
PermissionBackend permissionBackend,
GroupBackend groupBackend,
AccountCache accountCache,
- PatchListCache patchListCache,
+ DiffOperations diffOperations,
PatchSetUtil patchSetUtil,
ApprovalsUtil approvalsUtil,
Provider<FromAddressGenerator> fromAddressGenerator,
@@ -129,13 +130,14 @@
OutgoingEmailValidator validator,
@GerritInstanceName Provider<String> instanceNameProvider,
@GerritServerConfig Config cfg,
- Provider<CurrentUser> currentUserProvider) {
+ Provider<CurrentUser> currentUserProvider,
+ RetryHelper retryHelper) {
this.server = server;
this.projectCache = projectCache;
this.permissionBackend = permissionBackend;
this.groupBackend = groupBackend;
this.accountCache = accountCache;
- this.patchListCache = patchListCache;
+ this.diffOperations = diffOperations;
this.patchSetUtil = patchSetUtil;
this.approvalsUtil = approvalsUtil;
this.fromAddressGenerator = fromAddressGenerator;
@@ -158,8 +160,8 @@
this.accountQueryProvider = accountQueryProvider;
this.validator = validator;
this.instanceNameProvider = instanceNameProvider;
-
this.addInstanceNameInSubject = cfg.getBoolean("sendemail", "addInstanceNameInSubject", false);
this.currentUserProvider = currentUserProvider;
+ this.retryHelper = retryHelper;
}
}
diff --git a/java/com/google/gerrit/server/mail/send/MessageIdGenerator.java b/java/com/google/gerrit/server/mail/send/MessageIdGenerator.java
index aa683f6..b32c43a 100644
--- a/java/com/google/gerrit/server/mail/send/MessageIdGenerator.java
+++ b/java/com/google/gerrit/server/mail/send/MessageIdGenerator.java
@@ -58,8 +58,6 @@
/**
* Create a {@link MessageId} as a result of a change update.
*
- * @param repoView
- * @param patchsetId
* @return MessageId that depends on the patchset.
*/
public MessageId fromChangeUpdate(RepoView repoView, PatchSet.Id patchsetId) {
@@ -89,8 +87,9 @@
}
/**
- * @param accountId Create a {@link MessageId} as a result of an account update.
- * @return MessageId that depends on the account id.
+ * Create a {@link MessageId} as a result of an account update
+ *
+ * @return {@link MessageId} that depends on the account id.
*/
public MessageId fromAccountUpdate(Account.Id accountId) {
String userRef = RefNames.refsUsers(accountId);
@@ -113,8 +112,6 @@
* Create a {@link MessageId} from a reason, Account.Id, and timestamp.
*
* @param reason for performing this account update
- * @param accountId
- * @param timestamp
* @return MessageId that depends on the reason, accountId, and timestamp.
*/
public MessageId fromReasonAccountIdAndTimestamp(
diff --git a/java/com/google/gerrit/server/mail/send/ModifyReviewerSender.java b/java/com/google/gerrit/server/mail/send/ModifyReviewerSender.java
index dcf3b6c..b187f9c 100644
--- a/java/com/google/gerrit/server/mail/send/ModifyReviewerSender.java
+++ b/java/com/google/gerrit/server/mail/send/ModifyReviewerSender.java
@@ -37,5 +37,6 @@
super.init();
ccExistingReviewers();
+ removeUsersThatIgnoredTheChange();
}
}
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index ddcc0cf..8824cbd 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -18,6 +18,7 @@
import static com.google.gerrit.extensions.client.GeneralPreferencesInfo.EmailStrategy.DISABLED;
import static java.util.Objects.requireNonNull;
+import com.google.common.base.Throwables;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
@@ -34,6 +35,7 @@
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.change.NotifyResolver;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.update.RetryableAction.ActionType;
import com.google.gerrit.server.validators.OutgoingEmailValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.template.soy.jbcsrc.api.SoySauce;
@@ -93,12 +95,27 @@
this.messageId = messageId;
}
- /**
- * Format and enqueue the message for delivery.
- *
- * @throws EmailException
- */
+ /** Format and enqueue the message for delivery. */
public void send() throws EmailException {
+ try {
+ args.retryHelper
+ .action(
+ ActionType.SEND_EMAIL,
+ "sendEmail",
+ () -> {
+ sendImpl();
+ return null;
+ })
+ .retryWithTrace(Exception.class::isInstance)
+ .call();
+ } catch (Exception e) {
+ Throwables.throwIfUnchecked(e);
+ Throwables.throwIfInstanceOf(e, EmailException.class);
+ throw new EmailException("sending email failed", e);
+ }
+ }
+
+ private void sendImpl() throws EmailException {
if (!args.emailSender.isEnabled()) {
// Server has explicitly disabled email sending.
//
@@ -164,7 +181,8 @@
// drop them from the recipient lists, but only if the user is not being impersonated.
//
logger.atFine().log(
- "Not CCing email sender %s because the email strategy of this user is not %s but %s",
+ "Not CCing email sender %s because the email strategy of this user is not %s but"
+ + " %s",
fromUser.get().account().id(),
CC_ON_OWN_COMMENTS,
senderPrefs != null ? senderPrefs.getEmailStrategy() : null);
@@ -522,9 +540,9 @@
}
/**
+ * Returns whether this email is visible to the given account
+ *
* @param to account.
- * @throws PermissionBackendException
- * @return whether this email is visible to the given account.
*/
protected boolean isVisibleTo(Account.Id to) throws PermissionBackendException {
return true;
diff --git a/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java b/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
index a7c7757..d71f9ff 100644
--- a/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
+++ b/java/com/google/gerrit/server/notedb/AbstractChangeNotes.java
@@ -134,7 +134,7 @@
return changeId;
}
- /** @return revision of the metadata that was loaded. */
+ /** Returns revision of the metadata that was loaded. */
public ObjectId getRevision() {
return revision;
}
@@ -210,12 +210,12 @@
protected abstract void loadDefaults();
/**
- * @return the NameKey for the project where the notes should be stored, which is not necessarily
- * the same as the change's project.
+ * Returns the NameKey for the project where the notes should be stored, which is not necessarily
+ * the same as the change's project.
*/
public abstract Project.NameKey getProjectName();
- /** @return name of the reference storing this configuration. */
+ /** Returns name of the reference storing this configuration. */
protected abstract String getRefName();
/** Set up the metadata, parsing any state from the loaded revision. */
diff --git a/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java b/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
index 8e6606e..6677490 100644
--- a/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
+++ b/java/com/google/gerrit/server/notedb/AbstractChangeUpdate.java
@@ -122,12 +122,11 @@
}
/**
- * @return notes for the state of this change prior to this update. If this update is part of a
- * series managed by a {@link NoteDbUpdateManager}, then this reflects the state prior to the
- * first update in the series. A null return value can only happen when the change is being
- * rebuilt from NoteDb. A change that is in the process of being created will result in a
- * non-null return value from this method, but a null return value from {@link
- * ChangeNotes#getRevision()}.
+ * Returns notes for the state of this change prior to this update. If this update is part of a
+ * series managed by a {@link NoteDbUpdateManager}, then this reflects the state prior to the
+ * first update in the series. A null return value can only happen when the change is being
+ * rebuilt from NoteDb. A change that is in the process of being created will result in a non-null
+ * return value from this method, but a null return value from {@link ChangeNotes#getRevision()}.
*/
@Nullable
public ChangeNotes getNotes() {
@@ -173,8 +172,8 @@
}
/**
- * @return the NameKey for the project where the update will be stored, which is not necessarily
- * the same as the change's project.
+ * Returns the NameKey for the project where the update will be stored, which is not necessarily
+ * the same as the change's project.
*/
protected abstract Project.NameKey getProjectName();
diff --git a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
index afd8316..28ab711 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNoteUtil.java
@@ -40,6 +40,7 @@
static final FooterKey FOOTER_GROUPS = new FooterKey("Groups");
static final FooterKey FOOTER_HASHTAGS = new FooterKey("Hashtags");
static final FooterKey FOOTER_LABEL = new FooterKey("Label");
+ static final FooterKey FOOTER_COPIED_LABEL = new FooterKey("Copied-Label");
static final FooterKey FOOTER_PATCH_SET = new FooterKey("Patch-set");
static final FooterKey FOOTER_PATCH_SET_DESCRIPTION = new FooterKey("Patch-set-description");
static final FooterKey FOOTER_PRIVATE = new FooterKey("Private");
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotes.java b/java/com/google/gerrit/server/notedb/ChangeNotes.java
index 6684493..2d9b014 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotes.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotes.java
@@ -16,6 +16,7 @@
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.ImmutableListMultimap.toImmutableListMultimap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.gerrit.entities.RefNames.changeMetaRef;
import static java.util.Comparator.comparing;
@@ -36,6 +37,7 @@
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.google.common.flogger.FluentLogger;
+import com.google.errorprone.annotations.FormatMethod;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AttentionSetUpdate;
@@ -90,6 +92,7 @@
public static final Ordering<ChangeMessage> MESSAGE_BY_TIME =
Ordering.from(comparing(ChangeMessage::getWrittenOn));
+ @FormatMethod
public static ConfigInvalidException parseException(
Change.Id changeId, String fmt, Object... args) {
return new ConfigInvalidException("Change " + changeId + ": " + String.format(fmt, args));
@@ -336,6 +339,7 @@
// ChangeNotesCache from handlers.
private ImmutableSortedMap<PatchSet.Id, PatchSet> patchSets;
private ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvals;
+ private ImmutableListMultimap<PatchSet.Id, PatchSetApproval> approvalsWithCopied;
private ImmutableSet<Comment.Key> commentKeys;
public ChangeNotes(
@@ -373,28 +377,49 @@
return patchSets;
}
+ /**
+ * Gets the approvals, not including the copied approvals. To get copied approvals as well, use
+ * {@link #getApprovalsWithCopied}, or use {@code ApprovalInference}.
+ */
public ImmutableListMultimap<PatchSet.Id, PatchSetApproval> getApprovals() {
if (approvals == null) {
- approvals = ImmutableListMultimap.copyOf(state.approvals());
+ approvals =
+ state.approvals().stream()
+ .filter(e -> !e.getValue().copied())
+ .collect(toImmutableListMultimap(e -> e.getKey(), e -> e.getValue()));
}
return approvals;
}
+ /**
+ * This method is currently used only in tests. TODO(paiking): Use this method to fetch approvals
+ * (including copied approvals) instead of computing copied approvals on demand. This will be used
+ * by {@code ApprovalCache}.
+ *
+ * @return all approvals, including copied approvals.
+ */
+ public ImmutableListMultimap<PatchSet.Id, PatchSetApproval> getApprovalsWithCopied() {
+ if (approvalsWithCopied == null) {
+ approvalsWithCopied = ImmutableListMultimap.copyOf(state.approvals());
+ }
+ return approvalsWithCopied;
+ }
+
public ReviewerSet getReviewers() {
return state.reviewers();
}
- /** @return reviewers that do not currently have a Gerrit account and were added by email. */
+ /** Returns reviewers that do not currently have a Gerrit account and were added by email. */
public ReviewerByEmailSet getReviewersByEmail() {
return state.reviewersByEmail();
}
- /** @return reviewers that were modified during this change's current WIP phase. */
+ /** Returns reviewers that were modified during this change's current WIP phase. */
public ReviewerSet getPendingReviewers() {
return state.pendingReviewers();
}
- /** @return reviewers by email that were modified during this change's current WIP phase. */
+ /** Returns reviewers by email that were modified during this change's current WIP phase. */
public ReviewerByEmailSet getPendingReviewersByEmail() {
return state.pendingReviewersByEmail();
}
@@ -424,8 +449,8 @@
}
/**
- * @return an ImmutableSet of Account.Ids of all users that have been assigned to this change. The
- * order of the set is the order in which they were assigned.
+ * Returns an ImmutableSet of Account.Ids of all users that have been assigned to this change. The
+ * order of the set is the order in which they were assigned.
*/
public ImmutableSet<Account.Id> getPastAssignees() {
return Lists.reverse(state.assigneeUpdates()).stream()
@@ -436,37 +461,37 @@
}
/**
- * @return an ImmutableList of AssigneeStatusUpdate of all the updates to the assignee field to
- * this change. The order of the list is from most recent updates to least recent.
+ * Returns an ImmutableList of AssigneeStatusUpdate of all the updates to the assignee field to
+ * this change. The order of the list is from most recent updates to least recent.
*/
public ImmutableList<AssigneeStatusUpdate> getAssigneeUpdates() {
return state.assigneeUpdates();
}
- /** @return a ImmutableSet of all hashtags for this change sorted in alphabetical order. */
+ /** Returns an ImmutableSet of all hashtags for this change sorted in alphabetical order. */
public ImmutableSet<String> getHashtags() {
return ImmutableSortedSet.copyOf(state.hashtags());
}
- /** @return a list of all users who have ever been a reviewer on this change. */
+ /** Returns a list of all users who have ever been a reviewer on this change. */
public ImmutableList<Account.Id> getAllPastReviewers() {
return state.allPastReviewers();
}
/**
- * @return submit records stored during the most recent submit; only for changes that were
- * actually submitted.
+ * Returns submit records stored during the most recent submit; only for changes that were
+ * actually submitted.
*/
public ImmutableList<SubmitRecord> getSubmitRecords() {
return state.submitRecords();
}
- /** @return all change messages, in chronological order, oldest first. */
+ /** Returns all change messages, in chronological order, oldest first. */
public ImmutableList<ChangeMessage> getChangeMessages() {
return state.changeMessages();
}
- /** @return inline comments on each revision. */
+ /** Returns inline comments on each revision. */
public ImmutableListMultimap<ObjectId, HumanComment> getHumanComments() {
return state.publishedComments();
}
@@ -486,7 +511,7 @@
return state.updateCount();
}
- /** @return {@link Optional} value of time when the change was merged. */
+ /** Returns {@link Optional} value of time when the change was merged. */
public Optional<Timestamp> getMergedOn() {
return Optional.ofNullable(state.mergedOn());
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
index 87ad646..5cf3a64 100644
--- a/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
+++ b/java/com/google/gerrit/server/notedb/ChangeNotesParser.java
@@ -21,6 +21,7 @@
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHANGE_ID;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHERRY_PICK_OF;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COMMIT;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COPIED_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CURRENT;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_GROUPS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
@@ -55,6 +56,7 @@
import com.google.common.collect.Tables;
import com.google.common.flogger.FluentLogger;
import com.google.common.primitives.Ints;
+import com.google.errorprone.annotations.FormatMethod;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Address;
@@ -413,6 +415,9 @@
for (String line : commit.getFooterLineValues(FOOTER_LABEL)) {
parseApproval(psId, accountId, realAccountId, commitTimestamp, line);
}
+ for (String line : commit.getFooterLineValues(FOOTER_COPIED_LABEL)) {
+ parseCopiedApproval(psId, commitTimestamp, line);
+ }
for (ReviewerStateInternal state : ReviewerStateInternal.values()) {
for (String line : commit.getFooterLineValues(state.getFooterKey())) {
@@ -796,6 +801,69 @@
}
}
+ // Footer example: Copied-Label: <LABEL>=VOTE <Gerrit Account>,<Gerrit Real Account> :"<TAG>"
+ // ":<"TAG>"" is optional. <Gerrit Real Account> is also optional, if it was not set.
+ // The label, vote, and the Gerrit account are mandatory (unlike FOOTER_LABEL where Gerrit
+ // Account is also optional since by default it's the committer).
+ private void parseCopiedApproval(PatchSet.Id psId, Timestamp ts, String line)
+ throws ConfigInvalidException {
+ // Copied approvals can't be explicitly removed. They are removed the same way as non-copied
+ // approvals.
+ checkFooter(!line.startsWith("-"), FOOTER_COPIED_LABEL, line);
+
+ Account.Id accountId, realAccountId = null;
+ String labelVoteStr;
+ String tag = null;
+ int s = line.indexOf(' ');
+ int tagStart = line.indexOf(":\"");
+
+ // The first account is the accountId, and second (if applicable) is the realAccountId.
+ try {
+ labelVoteStr = line.substring(0, s);
+ } catch (StringIndexOutOfBoundsException ex) {
+ throw new ConfigInvalidException(ex.getMessage(), ex);
+ }
+ String[] identities =
+ line.substring(s + 1, tagStart == -1 ? line.length() : tagStart).split(",");
+ PersonIdent ident = RawParseUtils.parsePersonIdent(identities[0]);
+ checkFooter(ident != null, FOOTER_COPIED_LABEL, line);
+ accountId = parseIdent(ident);
+
+ if (identities.length > 1) {
+ PersonIdent realIdent = RawParseUtils.parsePersonIdent(identities[1]);
+ checkFooter(realIdent != null, FOOTER_COPIED_LABEL, line);
+ realAccountId = parseIdent(realIdent);
+ }
+
+ LabelVote l;
+ try {
+ l = LabelVote.parseWithEquals(labelVoteStr);
+ } catch (IllegalArgumentException e) {
+ ConfigInvalidException pe = parseException("invalid %s: %s", FOOTER_COPIED_LABEL, line);
+ pe.initCause(e);
+ throw pe;
+ }
+
+ if (tagStart != -1) {
+ // tagStart+2 skips ":\"" to parse the actual tag. Tags are in brackets.
+ // line.length()-1 skips the last ".
+ tag = line.substring(tagStart + 2, line.length() - 1);
+ }
+
+ PatchSetApproval.Builder psa =
+ PatchSetApproval.builder()
+ .key(PatchSetApproval.key(psId, accountId, LabelId.create(l.label())))
+ .value(l.value())
+ .granted(ts)
+ .tag(Optional.ofNullable(tag))
+ .copied(true);
+ if (realAccountId != null) {
+ psa.realAccountId(realAccountId);
+ }
+ approvals.putIfAbsent(psa.key(), psa);
+ bufferedApprovals.add(psa);
+ }
+
private void parseApproval(
PatchSet.Id psId, Account.Id accountId, Account.Id realAccountId, Timestamp ts, String line)
throws ConfigInvalidException {
@@ -917,6 +985,11 @@
}
} else {
checkFooter(rec != null, FOOTER_SUBMITTED_WITH, line);
+ if (line.startsWith("Rule-Name: ")) {
+ String ruleName = line.split(": ")[1];
+ rec.ruleName = ruleName;
+ continue;
+ }
SubmitRecord.Label label = new SubmitRecord.Label();
if (rec.labels == null) {
rec.labels = new ArrayList<>();
@@ -1167,6 +1240,7 @@
}
if (!missing.isEmpty()) {
throw parseException(
+ "%s",
"Missing footers: " + missing.stream().map(FooterKey::getName).collect(joining(", ")));
}
}
@@ -1200,6 +1274,7 @@
return pending != null && pending.commitId().isPresent();
}
+ @FormatMethod
private ConfigInvalidException parseException(String fmt, Object... args) {
return ChangeNotes.parseException(id, fmt, args);
}
diff --git a/java/com/google/gerrit/server/notedb/ChangeUpdate.java b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
index 971e0a8..5acea1b 100644
--- a/java/com/google/gerrit/server/notedb/ChangeUpdate.java
+++ b/java/com/google/gerrit/server/notedb/ChangeUpdate.java
@@ -24,6 +24,7 @@
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHANGE_ID;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CHERRY_PICK_OF;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COMMIT;
+import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_COPIED_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_CURRENT;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_GROUPS;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_HASHTAGS;
@@ -52,6 +53,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Table;
+import com.google.common.collect.Table.Cell;
import com.google.common.collect.TreeBasedTable;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Address;
@@ -61,6 +63,7 @@
import com.google.gerrit.entities.Comment;
import com.google.gerrit.entities.HumanComment;
import com.google.gerrit.entities.LabelId;
+import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RobotComment;
import com.google.gerrit.entities.SubmissionId;
@@ -128,6 +131,7 @@
private final ServiceUserClassifier serviceUserClassifier;
private final Table<String, Account.Id, Optional<Short>> approvals;
+ private final List<PatchSetApproval> copiedApprovals = new ArrayList<>();
private final Map<Account.Id, ReviewerStateInternal> reviewers = new LinkedHashMap<>();
private final Map<Address, ReviewerStateInternal> reviewersByEmail = new LinkedHashMap<>();
private final List<HumanComment> comments = new ArrayList<>();
@@ -273,6 +277,15 @@
approvals.put(label, reviewer, Optional.empty());
}
+ /**
+ * We expect the {@code copied} flag of {@code copiedPatchSetApproval} to be set, since this
+ * method is only meant for copied approvals.
+ */
+ public void putCopiedApproval(PatchSetApproval copiedPatchSetApproval) {
+ checkArgument(copiedPatchSetApproval.copied(), "Approval that should be copied is not copied.");
+ copiedApprovals.add(copiedPatchSetApproval);
+ }
+
public void merge(SubmissionId submissionId, Iterable<SubmitRecord> submitRecords) {
this.status = Change.Status.MERGED;
this.submissionId = submissionId.toString();
@@ -492,7 +505,7 @@
this.cherryPickOf = Optional.empty();
}
- /** @return the tree id for the updated tree */
+ /** Returns the tree id for the updated tree */
private ObjectId storeRevisionNotes(RevWalk rw, ObjectInserter inserter, ObjectId curr)
throws ConfigInvalidException, IOException {
if (submitRequirementResults.isEmpty() && comments.isEmpty() && pushCert == null) {
@@ -705,18 +718,10 @@
}
for (Table.Cell<String, Account.Id, Optional<Short>> c : approvals.cellSet()) {
- addFooter(msg, FOOTER_LABEL);
- // Label names/values are safe to append without sanitizing.
- if (!c.getValue().isPresent()) {
- msg.append('-').append(c.getRowKey());
- } else {
- msg.append(LabelVote.create(c.getRowKey(), c.getValue().get()).formatWithEquals());
- }
- Account.Id id = c.getColumnKey();
- if (!id.equals(getAccountId())) {
- noteUtil.appendAccountIdIdentString(msg.append(' '), id);
- }
- msg.append('\n');
+ addLabelFooter(msg, c);
+ }
+ for (PatchSetApproval patchSetApproval : copiedApprovals) {
+ addCopiedLabelFooter(msg, patchSetApproval);
}
if (submissionId != null) {
@@ -730,7 +735,10 @@
msg.append(' ').append(sanitizeFooter(rec.errorMessage));
}
msg.append('\n');
-
+ if (rec.ruleName != null) {
+ addFooter(msg, FOOTER_SUBMITTED_WITH).append("Rule-Name: ").append(rec.ruleName);
+ msg.append('\n');
+ }
if (rec.labels != null) {
for (SubmitRecord.Label label : rec.labels) {
// Label names/values are safe to append without sanitizing.
@@ -745,7 +753,6 @@
msg.append('\n');
}
}
- // TODO(maximeg) We might want to list plugins that validated this submission.
}
}
@@ -795,6 +802,47 @@
return cb;
}
+ private void addLabelFooter(StringBuilder msg, Cell<String, Account.Id, Optional<Short>> c) {
+ addFooter(msg, FOOTER_LABEL);
+ // Label names/values are safe to append without sanitizing.
+ if (!c.getValue().isPresent()) {
+ msg.append('-').append(c.getRowKey());
+ } else {
+ msg.append(LabelVote.create(c.getRowKey(), c.getValue().get()).formatWithEquals());
+ }
+ Account.Id id = c.getColumnKey();
+ if (!id.equals(getAccountId())) {
+ noteUtil.appendAccountIdIdentString(msg.append(' '), id);
+ }
+ msg.append('\n');
+ }
+
+ private void addCopiedLabelFooter(StringBuilder msg, PatchSetApproval patchSetApproval) {
+ if (patchSetApproval.value() == 0) {
+ // Can only happen if we removed a vote. There is no need to persist removed votes.
+ return;
+ }
+ addFooter(msg, FOOTER_COPIED_LABEL);
+ // Label names/values are safe to append without sanitizing.
+ msg.append(
+ LabelVote.create(patchSetApproval.label(), patchSetApproval.value()).formatWithEquals());
+ Account.Id id = patchSetApproval.accountId();
+ noteUtil.appendAccountIdIdentString(msg.append(' '), id);
+
+ // In the non-copied labels, we don't need to pass the real account id since it's already
+ // in FOOTER_REAL_USER. Here, we want to retain the original real account id.
+ if (patchSetApproval.realAccountId() != null) {
+ noteUtil.appendAccountIdIdentString(msg.append(","), patchSetApproval.realAccountId());
+ }
+
+ // In the non-copied labels, we don't need to pass the tag since it's already in
+ // FOOTER_TAG, but in this chase we want to retain the original tag, and not the current tag.
+ if (patchSetApproval.tag().isPresent()) {
+ msg.append(":\"" + sanitizeFooter(patchSetApproval.tag().get()) + "\"");
+ }
+ msg.append('\n');
+ }
+
private void clearAttentionSet(String reason) {
if (getNotes().getAttentionSet() == null) {
return;
@@ -990,6 +1038,7 @@
public boolean isEmpty() {
return commitSubject == null
&& approvals.isEmpty()
+ && copiedApprovals.isEmpty()
&& changeMessage == null
&& comments.isEmpty()
&& reviewers.isEmpty()
diff --git a/java/com/google/gerrit/server/notedb/CommitRewriter.java b/java/com/google/gerrit/server/notedb/CommitRewriter.java
index 549bd0f..7d743dc 100644
--- a/java/com/google/gerrit/server/notedb/CommitRewriter.java
+++ b/java/com/google/gerrit/server/notedb/CommitRewriter.java
@@ -13,16 +13,17 @@
// limitations under the License.
package com.google.gerrit.server.notedb;
+import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ASSIGNEE;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_ATTENTION;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_LABEL;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_REAL_USER;
import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_SUBMITTED_WITH;
-import static com.google.gerrit.server.notedb.ChangeNoteUtil.FOOTER_TAG;
import static com.google.gerrit.server.util.AccountTemplateUtil.ACCOUNT_TEMPLATE_PATTERN;
import static com.google.gerrit.server.util.AccountTemplateUtil.ACCOUNT_TEMPLATE_REGEX;
+import com.google.auto.value.AutoValue;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -38,7 +39,6 @@
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.git.RefUpdateUtil;
import com.google.gerrit.json.OutputFormat;
-import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
@@ -128,7 +128,7 @@
* Refs that were fixed by the run/ would be fixed if in --dry-run, together with their commit
* history diff. Diff is empty if --output-diff is false.
*/
- public Map<String, List<String>> fixedRefDiff = new HashMap<>();
+ public Map<String, List<CommitDiff>> fixedRefDiff = new HashMap<>();
/**
* Refs that still contain user data after the backfill run. Only filled if --verify-commits,
@@ -140,6 +140,20 @@
public List<String> refsFailedToFix = new ArrayList<>();
}
+ /** Diff result of a single commit rewrite */
+ @AutoValue
+ public abstract static class CommitDiff {
+ public static CommitDiff create(ObjectId oldSha1, String commitDiff) {
+ return new AutoValue_CommitRewriter_CommitDiff(oldSha1, commitDiff);
+ }
+
+ /** SHA1 of the overwritten commit */
+ public abstract ObjectId oldSha1();
+
+ /** Diff applied to the commit with {@link #oldSha1} */
+ public abstract String diff();
+ }
+
public static final String DEFAULT_ACCOUNT_REPLACEMENT = "Gerrit Account";
private static final Pattern NON_REPLACE_ACCOUNT_PATTERN =
@@ -156,10 +170,14 @@
Pattern.compile("Assignee changed from: (.*) to: (.*)");
private static final Pattern REMOVED_REVIEWER_PATTERN =
- Pattern.compile("Removed (cc|reviewer) (.*) .*");
+ Pattern.compile("Removed (cc|reviewer) (.*)(\\.| with the following votes)");
private static final Pattern REMOVED_VOTE_PATTERN = Pattern.compile("Removed (.*) by (.*)");
+ private static final String REMOVED_VOTES_CHANGE_MESSAGE_START = "Removed the following votes:";
+ private static final Pattern REMOVED_VOTES_CHANGE_MESSAGE_PATTERN =
+ Pattern.compile("\\* (.*) by (.*)");
+
private static final Pattern REMOVED_CHANGE_MESSAGE_PATTERN =
Pattern.compile("Change message removed by: (.*)(\nReason: .*)?");
@@ -168,10 +186,12 @@
private static final Pattern ON_CODE_OWNER_ADD_REVIEWER_PATTERN =
Pattern.compile("(.*) who was added as reviewer owns the following files");
- private static final Pattern ON_CODE_OWNER_APPROVAL_PATTERN =
- Pattern.compile("code-owner approved by (.*):");
- private static final Pattern ON_CODE_OWNER_OVERRIDE_PATTERN =
- Pattern.compile("code-owners submit requirement .* overridden by (.*):");
+ private static final String ON_CODE_OWNER_APPROVAL_REGEX = "code-owner approved by (.*):";
+ private static final String ON_CODE_OWNER_OVERRIDE_REGEX =
+ "code-owners submit requirement .* overridden by (.*)";
+
+ private static final Pattern ON_CODE_OWNER_REVIEW_PATTERN =
+ Pattern.compile(ON_CODE_OWNER_APPROVAL_REGEX + "|" + ON_CODE_OWNER_OVERRIDE_REGEX);
private static final Pattern REPLY_BY_REASON_PATTERN =
Pattern.compile("(.*) replied on the change");
@@ -179,6 +199,11 @@
Pattern.compile("Added by (.*) using the hovercard menu");
private static final Pattern REMOVED_BY_REASON_PATTERN =
Pattern.compile("Removed by (.*) using the hovercard menu");
+ private static final Pattern REMOVED_BY_ICON_CLICK_REASON_PATTERN =
+ Pattern.compile("Removed by (.*) by clicking the attention icon");
+
+ /** Matches {@link Account#getNameEmail} */
+ private static final Pattern NAME_EMAIL_PATTERN = Pattern.compile("(.*) (\\<.*\\>|\\(.*\\))");
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -211,6 +236,8 @@
try (RevWalk revWalk = new RevWalk(repo);
ObjectInserter ins = newPackInserter(repo)) {
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
+ bru.setForceRefLog(true);
+ bru.setRefLogMessage(CommitRewriter.class.getName(), false);
bru.setAllowNonFastForwards(true);
for (Ref ref : repo.getRefDatabase().getRefsByPrefix(RefNames.REFS_CHANGES)) {
Change.Id changeId = Change.Id.fromRef(ref.getName());
@@ -362,7 +389,8 @@
ChangeFixProgress changeFixProgress = new ChangeFixProgress();
while ((originalCommit = revWalk.next()) != null) {
- changeFixProgress.updateAuthorId = parseIdent(originalCommit.getAuthorIdent());
+ changeFixProgress.updateAuthorId =
+ parseIdent(changeFixProgress, originalCommit.getAuthorIdent());
PersonIdent fixedAuthorIdent;
if (changeFixProgress.updateAuthorId.isPresent()) {
fixedAuthorIdent =
@@ -378,8 +406,23 @@
? fixedCommitMessage.get()
: originalCommit.getFullMessage();
if (options.verifyCommits) {
- changeFixProgress.isValidAfterFix &=
- verifyCommit(commitMessage, fixedAuthorIdent, accountsInChange);
+ boolean isCommitValid = verifyCommit(commitMessage, fixedAuthorIdent, accountsInChange);
+ changeFixProgress.isValidAfterFix &= isCommitValid;
+ if (!isCommitValid) {
+ StringBuilder detailedVerificationStatus =
+ new StringBuilder(
+ String.format(
+ "Commit %s of ref %s failed verification after fix",
+ originalCommit.getId(), ref));
+ detailedVerificationStatus.append("\nCommit body:\n");
+ detailedVerificationStatus.append(commitMessage);
+ if (fixedCommitMessage.isPresent()) {
+ detailedVerificationStatus.append("\n was fixed.\n");
+ }
+ detailedVerificationStatus.append("Commit author:\n");
+ detailedVerificationStatus.append(fixedAuthorIdent.toString());
+ logger.atWarning().log(detailedVerificationStatus.toString());
+ }
}
boolean needsFix =
!fixedAuthorIdent.equals(originalCommit.getAuthorIdent())
@@ -411,7 +454,10 @@
"Expected diff for commit %s of ref %s",
originalCommit.getId(),
ref.getName());
- changeFixProgress.commitDiffs.add(diff);
+ changeFixProgress.commitDiffs.add(CommitDiff.create(originalCommit.getId(), diff));
+ } else if (needsFix) {
+ // Always output old commits SHA1
+ changeFixProgress.commitDiffs.add(CommitDiff.create(originalCommit.getId(), ""));
}
}
return changeFixProgress;
@@ -478,37 +524,46 @@
}
private Optional<String> fixAssigneeChangeMessage(
- Account.Id oldAssignee, Account.Id newAssignee, String originalChangeMessage) {
+ ChangeFixProgress changeFixProgress,
+ Optional<Account.Id> oldAssignee,
+ Optional<Account.Id> newAssignee,
+ String originalChangeMessage) {
if (Strings.isNullOrEmpty(originalChangeMessage)) {
return Optional.empty();
}
Matcher assigneeDeletedMatcher = ASSIGNEE_DELETED_PATTERN.matcher(originalChangeMessage);
if (assigneeDeletedMatcher.matches()) {
- if (!ACCOUNT_TEMPLATE_PATTERN.matcher(assigneeDeletedMatcher.group(1)).matches()) {
+ if (!NON_REPLACE_ACCOUNT_PATTERN.matcher(assigneeDeletedMatcher.group(1)).matches()) {
return Optional.of(
- "Assignee deleted: " + AccountTemplateUtil.getAccountTemplate(oldAssignee));
+ "Assignee deleted: "
+ + getPossibleAccountReplacement(
+ changeFixProgress, oldAssignee, assigneeDeletedMatcher.group(1)));
}
return Optional.empty();
}
Matcher assigneeAddedMatcher = ASSIGNEE_ADDED_PATTERN.matcher(originalChangeMessage);
if (assigneeAddedMatcher.matches()) {
- if (!ACCOUNT_TEMPLATE_PATTERN.matcher(assigneeAddedMatcher.group(1)).matches()) {
+ if (!NON_REPLACE_ACCOUNT_PATTERN.matcher(assigneeAddedMatcher.group(1)).matches()) {
return Optional.of(
- "Assignee added: " + AccountTemplateUtil.getAccountTemplate(newAssignee));
+ "Assignee added: "
+ + getPossibleAccountReplacement(
+ changeFixProgress, newAssignee, assigneeAddedMatcher.group(1)));
}
return Optional.empty();
}
Matcher assigneeChangedMatcher = ASSIGNEE_CHANGED_PATTERN.matcher(originalChangeMessage);
if (assigneeChangedMatcher.matches()) {
- if (!ACCOUNT_TEMPLATE_PATTERN.matcher(assigneeChangedMatcher.group(1)).matches()) {
+ if (!NON_REPLACE_ACCOUNT_PATTERN.matcher(assigneeChangedMatcher.group(1)).matches()) {
return Optional.of(
String.format(
"Assignee changed from: %s to: %s",
- AccountTemplateUtil.getAccountTemplate(oldAssignee),
- AccountTemplateUtil.getAccountTemplate(newAssignee)));
+ getPossibleAccountReplacement(
+ changeFixProgress, oldAssignee, assigneeChangedMatcher.group(1)),
+ getPossibleAccountReplacement(
+ changeFixProgress, newAssignee, assigneeChangedMatcher.group(2))));
}
return Optional.empty();
}
@@ -520,7 +575,8 @@
return Optional.empty();
}
Matcher matcher = REMOVED_REVIEWER_PATTERN.matcher(originalChangeMessage);
- if (matcher.matches() && !ACCOUNT_TEMPLATE_PATTERN.matcher(matcher.group(2)).matches()) {
+
+ if (matcher.find() && !ACCOUNT_TEMPLATE_PATTERN.matcher(matcher.group(2)).matches()) {
// Since we do not use change messages for reviewer updates on UI, it does not matter what we
// rewrite it to.
return Optional.of(originalChangeMessage.substring(0, matcher.end(1)));
@@ -529,24 +585,53 @@
}
private Optional<String> fixRemoveVoteChangeMessage(
- Optional<Account.Id> reviewer, String originalChangeMessage) {
+ ChangeFixProgress changeFixProgress,
+ Optional<Account.Id> reviewer,
+ String originalChangeMessage) {
if (Strings.isNullOrEmpty(originalChangeMessage)) {
return Optional.empty();
}
Matcher matcher = REMOVED_VOTE_PATTERN.matcher(originalChangeMessage);
- if (matcher.matches() && !ACCOUNT_TEMPLATE_PATTERN.matcher(matcher.group(2)).matches()) {
+ if (matcher.matches() && !NON_REPLACE_ACCOUNT_PATTERN.matcher(matcher.group(2)).matches()) {
return Optional.of(
String.format(
"Removed %s by %s",
matcher.group(1),
- reviewer
- .map(AccountTemplateUtil::getAccountTemplate)
- .orElse(DEFAULT_ACCOUNT_REPLACEMENT)));
+ getPossibleAccountReplacement(
+ changeFixProgress, reviewer, getNameFromNameEmail(matcher.group(2)))));
}
return Optional.empty();
}
+ private Optional<String> fixRemoveVotesChangeMessage(
+ ChangeFixProgress changeFixProgress, String originalChangeMessage) {
+ if (Strings.isNullOrEmpty(originalChangeMessage)
+ || !originalChangeMessage.startsWith(REMOVED_VOTES_CHANGE_MESSAGE_START)) {
+ return Optional.empty();
+ }
+ String[] lines = originalChangeMessage.split("\\r?\\n");
+ StringBuilder fixedLines = new StringBuilder();
+ for (int i = 1; i < lines.length; i++) {
+ if (lines[i].isEmpty()) {
+ continue;
+ }
+ Matcher matcher = REMOVED_VOTES_CHANGE_MESSAGE_PATTERN.matcher(lines[i]);
+ if (matcher.matches() && !NON_REPLACE_ACCOUNT_PATTERN.matcher(matcher.group(2)).matches()) {
+ fixedLines.append(
+ String.format(
+ "* %s by %s\n",
+ matcher.group(1),
+ getPossibleAccountReplacement(
+ changeFixProgress, Optional.empty(), getNameFromNameEmail(matcher.group(2)))));
+ }
+ }
+ if (fixedLines.length() == 0) {
+ return Optional.empty();
+ }
+ return Optional.of(REMOVED_VOTES_CHANGE_MESSAGE_START + "\n" + fixedLines);
+ }
+
private Optional<String> fixDeleteChangeMessageCommitMessage(String originalChangeMessage) {
if (Strings.isNullOrEmpty(originalChangeMessage)) {
return Optional.empty();
@@ -589,43 +674,20 @@
Matcher onAddReviewerMatcher = ON_CODE_OWNER_ADD_REVIEWER_PATTERN.matcher(originalMessage);
if (!onAddReviewerMatcher.find()
- || NON_REPLACE_ACCOUNT_PATTERN.matcher(onAddReviewerMatcher.group(1)).matches()) {
+ || NON_REPLACE_ACCOUNT_PATTERN
+ .matcher(normalizeOnCodeOwnerAddReviewerMatch(onAddReviewerMatcher.group(1)))
+ .matches()) {
return Optional.empty();
}
// Pre fix, try to replace with something meaningful.
// Retrieve reviewer accounts from cache and try to match by their name.
- Map<Account.Id, AccountState> missingUserNameReviewers =
- accountCache.get(
- changeFixProgress.parsedReviewers.entrySet().stream()
- .filter(entry -> entry.getValue().isEmpty())
- .map(Map.Entry::getKey)
- .collect(ImmutableSet.toImmutableSet()));
- // TODO(mariasavtchouk): Adjust based on the dry run.
- // We could just reset parsedReviewers here, because next message should only include the delta
- changeFixProgress.parsedReviewers.putAll(
- missingUserNameReviewers.entrySet().stream()
- .collect(
- ImmutableMap.toImmutableMap(
- Map.Entry::getKey, e -> e.getValue().account().getName())));
onAddReviewerMatcher.reset();
StringBuffer sb = new StringBuffer();
while (onAddReviewerMatcher.find()) {
- String reviewerName = onAddReviewerMatcher.group(1);
- Set<Account.Id> possibleReplacements =
- changeFixProgress.parsedReviewers.entrySet().stream()
- .filter(reviewer -> reviewer.getValue().equals(reviewerName))
- .map(Entry::getKey)
- .collect(ImmutableSet.toImmutableSet());
- String replacementName = DEFAULT_ACCOUNT_REPLACEMENT;
- if (possibleReplacements.isEmpty()) {
- logger.atWarning().log("Could not find reviewer account matching name %s", reviewerName);
- } else if (possibleReplacements.size() > 1) {
- logger.atWarning().log("Found multiple reviewer account matching name %s", reviewerName);
- } else {
- replacementName =
- AccountTemplateUtil.getAccountTemplate(Iterables.getOnlyElement(possibleReplacements));
- }
+ String reviewerName = normalizeOnCodeOwnerAddReviewerMatch(onAddReviewerMatcher.group(1));
+ String replacementName =
+ getPossibleAccountReplacement(changeFixProgress, Optional.empty(), reviewerName);
onAddReviewerMatcher.appendReplacement(
sb, replacementName + ", who was added as reviewer owns the following files");
}
@@ -634,36 +696,42 @@
return Optional.of(sb.toString());
}
+ /**
+ * See {@link #ON_CODE_OWNER_ADD_REVIEWER_PATTERN}.
+ *
+ * <p>Some of the messages have format '{@link AccountTemplateUtil#ACCOUNT_TEMPLATE}, who...',
+ * while others '{@link AccountTemplateUtil#ACCOUNT_TEMPLATE} who...'.
+ *
+ * <p>Cut the trailing ',' from the match, so that valid patterns are not replaced.
+ */
+ private static String normalizeOnCodeOwnerAddReviewerMatch(String reviewerMatch) {
+ String reviewerName = reviewerMatch;
+ if (reviewerName.charAt(reviewerName.length() - 1) == ',') {
+ reviewerName = reviewerName.substring(0, reviewerName.length() - 1);
+ }
+ return reviewerName;
+ }
+
private Optional<String> fixCodeOwnersOnReviewChangeMessage(
Optional<Account.Id> reviewer, String originalMessage) {
if (Strings.isNullOrEmpty(originalMessage)) {
return Optional.empty();
}
- Matcher onCodeOwnerApprovalMatcher = ON_CODE_OWNER_APPROVAL_PATTERN.matcher(originalMessage);
- if (onCodeOwnerApprovalMatcher.find()
- && !ACCOUNT_TEMPLATE_PATTERN.matcher(onCodeOwnerApprovalMatcher.group(1)).matches()) {
- return Optional.of(
- originalMessage.replace(
- "approved by " + onCodeOwnerApprovalMatcher.group(1),
- "approved by "
- + reviewer
- .map(AccountTemplateUtil::getAccountTemplate)
- .orElse(DEFAULT_ACCOUNT_REPLACEMENT))
- + "\n");
- }
-
- Matcher onCodeOwnerOverrideMatcher = ON_CODE_OWNER_OVERRIDE_PATTERN.matcher(originalMessage);
- if (onCodeOwnerOverrideMatcher.find()
- && !ACCOUNT_TEMPLATE_PATTERN.matcher(onCodeOwnerOverrideMatcher.group(1)).matches()) {
- return Optional.of(
- originalMessage.replace(
- "overridden by " + onCodeOwnerOverrideMatcher.group(1),
- "overridden by "
- + reviewer
- .map(AccountTemplateUtil::getAccountTemplate)
- .orElse(DEFAULT_ACCOUNT_REPLACEMENT))
- + "\n");
+ Matcher onCodeOwnerReviewMatcher = ON_CODE_OWNER_REVIEW_PATTERN.matcher(originalMessage);
+ while (onCodeOwnerReviewMatcher.find()) {
+ String accountName =
+ firstNonNull(onCodeOwnerReviewMatcher.group(1), onCodeOwnerReviewMatcher.group(2));
+ if (!ACCOUNT_TEMPLATE_PATTERN.matcher(accountName).matches()) {
+ return Optional.of(
+ originalMessage.replace(
+ "by " + accountName,
+ "by "
+ + reviewer
+ .map(AccountTemplateUtil::getAccountTemplate)
+ .orElse(DEFAULT_ACCOUNT_REPLACEMENT))
+ + "\n");
+ }
}
return Optional.empty();
@@ -694,6 +762,14 @@
return Optional.of("Removed by someone using the hovercard menu");
}
+
+ Matcher removedByIconClickReasonMatcher =
+ REMOVED_BY_ICON_CLICK_REASON_PATTERN.matcher(originalReason);
+ if (removedByIconClickReasonMatcher.matches()
+ && !OK_ACCOUNT_NAME_PATTERN.matcher(removedByIconClickReasonMatcher.group(1)).matches()) {
+
+ return Optional.of("Removed by someone by clicking the attention icon");
+ }
return Optional.empty();
}
@@ -733,22 +809,22 @@
for (FooterLine fl : footerLines) {
String footerKey = fl.getKey();
String footerValue = fl.getValue();
- if (footerKey.equalsIgnoreCase(FOOTER_TAG.getName())) {
- if (footerValue.equals(ChangeMessagesUtil.TAG_MERGED) && !fixedChangeMessage.isPresent()) {
- fixedChangeMessage = fixSubmitChangeMessage(originalChangeMessage);
- }
- } else if (footerKey.equalsIgnoreCase(FOOTER_ASSIGNEE.getName())) {
+ if (footerKey.equalsIgnoreCase(FOOTER_ASSIGNEE.getName())) {
Account.Id oldAssignee = fixProgress.assigneeId;
FixIdentResult fixedAssignee = null;
if (footerValue.equals("")) {
fixProgress.assigneeId = null;
} else {
- fixedAssignee = getFixedIdentString(footerValue);
+ fixedAssignee = getFixedIdentString(fixProgress, footerValue);
fixProgress.assigneeId = fixedAssignee.accountId;
}
if (!fixedChangeMessage.isPresent()) {
fixedChangeMessage =
- fixAssigneeChangeMessage(oldAssignee, fixProgress.assigneeId, originalChangeMessage);
+ fixAssigneeChangeMessage(
+ fixProgress,
+ Optional.ofNullable(oldAssignee),
+ Optional.ofNullable(fixProgress.assigneeId),
+ originalChangeMessage);
}
if (fixedAssignee != null && fixedAssignee.fixedIdentString.isPresent()) {
addFooter(footerLinesBuilder, footerKey, fixedAssignee.fixedIdentString.get());
@@ -760,15 +836,14 @@
if (!fixedChangeMessage.isPresent()) {
fixedChangeMessage = fixReviewerChangeMessage(originalChangeMessage);
}
- FixIdentResult fixedReviewer = getFixedIdentString(footerValue);
- fixProgress.parsedReviewers.putIfAbsent(fixedReviewer.accountId, "");
+ FixIdentResult fixedReviewer = getFixedIdentString(fixProgress, footerValue);
if (fixedReviewer.fixedIdentString.isPresent()) {
addFooter(footerLinesBuilder, footerKey, fixedReviewer.fixedIdentString.get());
anyFootersFixed = true;
continue;
}
} else if (footerKey.equalsIgnoreCase(FOOTER_REAL_USER.getName())) {
- FixIdentResult fixedRealUser = getFixedIdentString(footerValue);
+ FixIdentResult fixedRealUser = getFixedIdentString(fixProgress, footerValue);
if (fixedRealUser.fixedIdentString.isPresent()) {
addFooter(footerLinesBuilder, footerKey, fixedRealUser.fixedIdentString.get());
anyFootersFixed = true;
@@ -779,11 +854,12 @@
FixIdentResult fixedVoter = null;
if (voterIdentStart > 0) {
String originalIdentString = footerValue.substring(voterIdentStart + 1);
- fixedVoter = getFixedIdentString(originalIdentString);
+ fixedVoter = getFixedIdentString(fixProgress, originalIdentString);
}
if (!fixedChangeMessage.isPresent()) {
fixedChangeMessage =
fixRemoveVoteChangeMessage(
+ fixProgress,
fixedVoter == null
? fixProgress.updateAuthorId
: Optional.of(fixedVoter.accountId),
@@ -803,7 +879,7 @@
int voterIdentStart = StringUtils.ordinalIndexOf(footerValue, ": ", 2);
if (voterIdentStart >= 0) {
String originalIdentString = footerValue.substring(voterIdentStart + 2);
- FixIdentResult fixedVoter = getFixedIdentString(originalIdentString);
+ FixIdentResult fixedVoter = getFixedIdentString(fixProgress, originalIdentString);
if (fixedVoter.fixedIdentString.isPresent()) {
String fixedLabelVote =
footerValue.substring(0, voterIdentStart)
@@ -819,7 +895,7 @@
AttentionStatusInNoteDb originalAttentionSetUpdate =
gson.fromJson(footerValue, AttentionStatusInNoteDb.class);
FixIdentResult fixedAttentionAccount =
- getFixedIdentString(originalAttentionSetUpdate.personIdent);
+ getFixedIdentString(fixProgress, originalAttentionSetUpdate.personIdent);
Optional<String> fixedReason = fixAttentionSetReason(originalAttentionSetUpdate.reason);
if (fixedAttentionAccount.fixedIdentString.isPresent() || fixedReason.isPresent()) {
AttentionStatusInNoteDb fixedAttentionSetUpdate =
@@ -836,7 +912,27 @@
}
addFooter(footerLinesBuilder, footerKey, footerValue);
}
-
+ // Some of the old commits are missing corresponding footers but still have change messages that
+ // need the fix. For such cases, try to guess or replace with the default string (see
+ // getPossibleAccountReplacement)
+ if (!fixedChangeMessage.isPresent()) {
+ fixedChangeMessage = fixReviewerChangeMessage(originalChangeMessage);
+ }
+ if (!fixedChangeMessage.isPresent()) {
+ fixedChangeMessage = fixRemoveVotesChangeMessage(fixProgress, originalChangeMessage);
+ }
+ if (!fixedChangeMessage.isPresent()) {
+ fixedChangeMessage =
+ fixRemoveVoteChangeMessage(fixProgress, Optional.empty(), originalChangeMessage);
+ }
+ if (!fixedChangeMessage.isPresent()) {
+ fixedChangeMessage =
+ fixAssigneeChangeMessage(
+ fixProgress, Optional.empty(), Optional.empty(), originalChangeMessage);
+ }
+ if (!fixedChangeMessage.isPresent()) {
+ fixedChangeMessage = fixSubmitChangeMessage(originalChangeMessage);
+ }
if (!fixedChangeMessage.isPresent()) {
fixedChangeMessage = fixDeleteChangeMessageCommitMessage(originalChangeMessage);
}
@@ -872,9 +968,11 @@
return sb;
}
- private Optional<Account.Id> parseIdent(PersonIdent ident) {
+ private Optional<Account.Id> parseIdent(ChangeFixProgress changeFixProgress, PersonIdent ident) {
Optional<Account.Id> account = NoteDbUtil.parseIdent(ident);
- if (!account.isPresent()) {
+ if (account.isPresent()) {
+ changeFixProgress.parsedAccounts.putIfAbsent(account.get(), "");
+ } else {
logger.atWarning().log("Failed to parse id %s", ident);
}
return account;
@@ -896,20 +994,22 @@
* Parses {@code originalIdentString} and applies the fix, so it does not contain user data, see
* {@link ChangeNoteUtil#appendAccountIdIdentString}.
*
+ * @param changeFixProgress see {@link ChangeFixProgress}
* @param originalIdentString ident to apply the fix to.
* @return {@link FixIdentResult}, with {@link FixIdentResult#accountId} parsed from {@code
* originalIdentString} and {@link FixIdentResult#fixedIdentString} if the fix was applied.
* @throws ConfigInvalidException if could not parse {@link FixIdentResult#accountId} from {@code
* originalIdentString}
*/
- private FixIdentResult getFixedIdentString(String originalIdentString)
+ private FixIdentResult getFixedIdentString(
+ ChangeFixProgress changeFixProgress, String originalIdentString)
throws ConfigInvalidException {
FixIdentResult fixIdentResult = new FixIdentResult();
PersonIdent originalIdent = RawParseUtils.parsePersonIdent(originalIdentString);
// Ident as String is saved in NoteDB footers, if this fails to parse, something is
// wrong with the change and we better not touch it.
fixIdentResult.accountId =
- parseIdent(originalIdent)
+ parseIdent(changeFixProgress, originalIdent)
.orElseThrow(
() -> new ConfigInvalidException("field to parse id: " + originalIdentString));
String fixedIdentString =
@@ -922,6 +1022,59 @@
return fixIdentResult;
}
+ /** Extracts {@link Account#getName} from {@link Account#getNameEmail} */
+ private String getNameFromNameEmail(String nameEmail) {
+ Matcher nameEmailMatcher = NAME_EMAIL_PATTERN.matcher(nameEmail);
+ return nameEmailMatcher.matches() ? nameEmailMatcher.group(1) : nameEmail;
+ }
+
+ /**
+ * Returns replacement for {@code accountName}.
+ *
+ * <p>If {@code account} is known, replace with {@link AccountTemplateUtil#getAccountTemplate}.
+ * Otherwise, try to guess the correct replacement account for {@code accountName} among {@link
+ * ChangeFixProgress#parsedAccounts} that appeared in the change. If this fails {@link
+ * #DEFAULT_ACCOUNT_REPLACEMENT} is applied.
+ *
+ * @param changeFixProgress see {@link ChangeFixProgress}
+ * @param account account that should be used for replacement, if known
+ * @param accountName {@link Account#getName} to replace.
+ * @return replacement for {@code accountName}
+ */
+ private String getPossibleAccountReplacement(
+ ChangeFixProgress changeFixProgress, Optional<Account.Id> account, String accountName) {
+ if (account.isPresent()) {
+ return AccountTemplateUtil.getAccountTemplate(account.get());
+ }
+ // Retrieve reviewer accounts from cache and try to match by their name.
+ Map<Account.Id, AccountState> missingUserNameReviewers =
+ accountCache.get(
+ changeFixProgress.parsedAccounts.entrySet().stream()
+ .filter(entry -> entry.getValue().isEmpty())
+ .map(Map.Entry::getKey)
+ .collect(ImmutableSet.toImmutableSet()));
+ changeFixProgress.parsedAccounts.putAll(
+ missingUserNameReviewers.entrySet().stream()
+ .collect(
+ ImmutableMap.toImmutableMap(
+ Map.Entry::getKey, e -> e.getValue().account().getName())));
+ Set<Account.Id> possibleReplacements =
+ changeFixProgress.parsedAccounts.entrySet().stream()
+ .filter(e -> e.getValue().equals(accountName))
+ .map(Entry::getKey)
+ .collect(ImmutableSet.toImmutableSet());
+ String replacementName = DEFAULT_ACCOUNT_REPLACEMENT;
+ if (possibleReplacements.isEmpty()) {
+ logger.atWarning().log("Could not find reviewer account matching name %s", accountName);
+ } else if (possibleReplacements.size() > 1) {
+ logger.atWarning().log("Found multiple reviewer account matching name %s", accountName);
+ } else {
+ replacementName =
+ AccountTemplateUtil.getAccountTemplate(Iterables.getOnlyElement(possibleReplacements));
+ }
+ return replacementName;
+ }
+
/**
* Cuts tree and parent lines from raw unparsed commit body, so they are not included in diff
* comparison.
@@ -989,11 +1142,11 @@
Optional<Account.Id> updateAuthorId = null;
/**
- * Reviewer accounts parsed so far together with their {@link Account#getName} extracted from
- * {@link #accountCache} if needed by rewrite. Maps to empty string if was not requested from
- * cache yet.
+ * Accounts parsed so far together with their {@link Account#getName} extracted from {@link
+ * #accountCache} if needed by rewrite. Maps to empty string if was not requested from cache
+ * yet.
*/
- Map<Account.Id, String> parsedReviewers = new HashMap<>();
+ Map<Account.Id, String> parsedAccounts = new HashMap<>();
/** Id of the current commit in rewriter walk. */
ObjectId newTipId = null;
@@ -1006,6 +1159,6 @@
*/
boolean isValidAfterFix = true;
- List<String> commitDiffs = new ArrayList<>();
+ List<CommitDiff> commitDiffs = new ArrayList<>();
}
}
diff --git a/java/com/google/gerrit/server/notedb/DeleteChangeMessageRewriter.java b/java/com/google/gerrit/server/notedb/DeleteChangeMessageRewriter.java
index e07c793..6d6d53d 100644
--- a/java/com/google/gerrit/server/notedb/DeleteChangeMessageRewriter.java
+++ b/java/com/google/gerrit/server/notedb/DeleteChangeMessageRewriter.java
@@ -110,7 +110,6 @@
* @param commitMessage the full commit message of the new commit.
* @param inserter the {@code ObjectInserter} for the rewrite process.
* @return the {@code objectId} of the new commit.
- * @throws IOException
*/
private ObjectId rewriteOneCommit(
RevCommit originalCommit,
diff --git a/java/com/google/gerrit/server/notedb/DeleteCommentRewriter.java b/java/com/google/gerrit/server/notedb/DeleteCommentRewriter.java
index d0b6247..e8c0fda 100644
--- a/java/com/google/gerrit/server/notedb/DeleteCommentRewriter.java
+++ b/java/com/google/gerrit/server/notedb/DeleteCommentRewriter.java
@@ -191,8 +191,6 @@
* @param putInComments the comments put in by this commit.
* @param deletedComments the comments deleted by this commit.
* @return the {@code objectId} of the new commit.
- * @throws IOException
- * @throws ConfigInvalidException
*/
private ObjectId rewriteCommit(
RevCommit originalCommit,
diff --git a/java/com/google/gerrit/server/notedb/Sequences.java b/java/com/google/gerrit/server/notedb/Sequences.java
index 7a8e28f..7ae98778 100644
--- a/java/com/google/gerrit/server/notedb/Sequences.java
+++ b/java/com/google/gerrit/server/notedb/Sequences.java
@@ -112,8 +112,11 @@
.setCumulative()
.setUnit(Units.MILLISECONDS),
Field.ofEnum(SequenceType.class, "sequence", Metadata.Builder::noteDbSequenceType)
+ .description("The sequence from which IDs were retrieved.")
.build(),
- Field.ofBoolean("multiple", Metadata.Builder::multiple).build());
+ Field.ofBoolean("multiple", Metadata.Builder::multiple)
+ .description("Whether more than one ID was retrieved.")
+ .build());
}
public int nextAccountId() {
diff --git a/java/com/google/gerrit/server/notedb/StoreSubmitRequirementsOp.java b/java/com/google/gerrit/server/notedb/StoreSubmitRequirementsOp.java
index 4d99f93..57a3cd7 100644
--- a/java/com/google/gerrit/server/notedb/StoreSubmitRequirementsOp.java
+++ b/java/com/google/gerrit/server/notedb/StoreSubmitRequirementsOp.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.notedb;
-import com.google.gerrit.entities.Change;
import com.google.gerrit.server.project.SubmitRequirementsEvaluator;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.update.BatchUpdateOp;
@@ -39,10 +38,19 @@
@Override
public boolean updateChange(ChangeContext ctx) throws Exception {
- Change change = ctx.getChange();
- ChangeData changeData = changeDataFactory.create(change);
- ChangeUpdate update = ctx.getUpdate(change.currentPatchSetId());
- update.putSubmitRequirementResults(evaluator.getResults(changeData).values());
+ // Create ChangeData using the project/change IDs instead of ctx.getChange(). We do that because
+ // for changes requiring a rebase before submission (e.g. if submit type = RebaseAlways), the
+ // RebaseOp inserts a new patchset that is visible here (via Change#getCurrentPatchset). If we
+ // then try to get ChangeData#currentPatchset it will return null, since it loads patchsets from
+ // NoteDb but tries to find the patchset with the ID of the one just inserted by the rebase op.
+ // Note that this implementation means that, in this case, submit requirement results will be
+ // stored in change notes of the pre last patchset commit. This is fine since submit requirement
+ // results should evaluate to the exact same results for both commits. Additionally, the
+ // pre-last commit is the one for which we displayed the submit requirement results of the last
+ // patchset to the user before it was merged.
+ ChangeData changeData = changeDataFactory.create(ctx.getProject(), ctx.getChange().getId());
+ ChangeUpdate update = ctx.getUpdate(ctx.getChange().currentPatchSetId());
+ update.putSubmitRequirementResults(evaluator.evaluateAllRequirements(changeData).values());
return !changeData.submitRequirements().isEmpty();
}
}
diff --git a/java/com/google/gerrit/server/notedb/SubmitRequirementProtoConverter.java b/java/com/google/gerrit/server/notedb/SubmitRequirementProtoConverter.java
index 416b850..9bf56d8 100644
--- a/java/com/google/gerrit/server/notedb/SubmitRequirementProtoConverter.java
+++ b/java/com/google/gerrit/server/notedb/SubmitRequirementProtoConverter.java
@@ -40,6 +40,7 @@
SubmitRequirementResultProto.Builder builder = SubmitRequirementResultProto.newBuilder();
builder
.setSubmitRequirement(SubmitRequirementSerializer.serialize(r.submitRequirement()))
+ .setLegacy(r.legacy())
.setCommit(ObjectIdConverter.create().toByteString(r.patchSetCommitId()));
if (r.applicabilityExpressionResult().isPresent()) {
builder.setApplicabilityExpressionResult(
@@ -60,6 +61,7 @@
public SubmitRequirementResult fromProto(SubmitRequirementResultProto proto) {
SubmitRequirementResult.Builder builder =
SubmitRequirementResult.builder()
+ .legacy(proto.getLegacy())
.patchSetCommitId(ObjectIdConverter.create().fromByteString(proto.getCommit()))
.submitRequirement(
SubmitRequirementSerializer.deserialize(proto.getSubmitRequirement()));
diff --git a/java/com/google/gerrit/server/patch/AutoMerger.java b/java/com/google/gerrit/server/patch/AutoMerger.java
index 97910400..2529c04 100644
--- a/java/com/google/gerrit/server/patch/AutoMerger.java
+++ b/java/com/google/gerrit/server/patch/AutoMerger.java
@@ -100,18 +100,22 @@
MetricMaker metricMaker,
@GerritServerConfig Config cfg,
@GerritPersonIdent Provider<PersonIdent> gerritIdentProvider) {
+ Field<OperationType> operationTypeField =
+ Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName)
+ .description("The type of the operation (CACHE_LOAD, IN_MEMORY_WRITE, ON_DISK_WRITE).")
+ .build();
this.counter =
metricMaker.newCounter(
"git/auto-merge/num_operations",
new Description("AutoMerge computations").setRate().setUnit("auto merge computations"),
- Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName).build());
+ operationTypeField);
this.latency =
metricMaker.newTimer(
"git/auto-merge/latency",
new Description("AutoMerge computation latency")
.setCumulative()
.setUnit("milliseconds"),
- Field.ofEnum(OperationType.class, "type", Metadata.Builder::operationName).build());
+ operationTypeField);
this.save = cacheAutomerge(cfg);
this.gerritIdentProvider = gerritIdentProvider;
this.configuredMergeStrategy = MergeUtil.getMergeStrategy(cfg);
diff --git a/java/com/google/gerrit/server/patch/DiffSummaryLoader.java b/java/com/google/gerrit/server/patch/DiffSummaryLoader.java
index b61e0c7..fcce672 100644
--- a/java/com/google/gerrit/server/patch/DiffSummaryLoader.java
+++ b/java/com/google/gerrit/server/patch/DiffSummaryLoader.java
@@ -16,58 +16,73 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Callable;
+import org.eclipse.jgit.lib.ObjectId;
public class DiffSummaryLoader implements Callable<DiffSummary> {
public interface Factory {
DiffSummaryLoader create(DiffSummaryKey key, Project.NameKey project);
}
- private final PatchListCache patchListCache;
+ private final DiffOperations diffOperations;
private final DiffSummaryKey key;
private final Project.NameKey project;
@Inject
- DiffSummaryLoader(PatchListCache plc, @Assisted DiffSummaryKey k, @Assisted Project.NameKey p) {
- patchListCache = plc;
+ DiffSummaryLoader(
+ DiffOperations diffOps, @Assisted DiffSummaryKey k, @Assisted Project.NameKey p) {
+ diffOperations = diffOps;
key = k;
project = p;
}
@Override
public DiffSummary call() throws Exception {
- PatchList patchList = patchListCache.get(key.toPatchListKey(), project);
- return toDiffSummary(patchList);
+ ObjectId oldId = key.toPatchListKey().getOldId();
+ ObjectId newId = key.toPatchListKey().getNewId();
+ Map<String, FileDiffOutput> diffList =
+ oldId == null
+ ? diffOperations.listModifiedFilesAgainstParent(project, newId, /* parentNum= */ 0)
+ : diffOperations.listModifiedFiles(project, oldId, newId);
+ return toDiffSummary(diffList);
}
- private DiffSummary toDiffSummary(PatchList patchList) {
- List<String> r = new ArrayList<>(patchList.getPatches().size());
- for (PatchListEntry e : patchList.getPatches()) {
- if (Patch.isMagic(e.getNewName())) {
+ private DiffSummary toDiffSummary(Map<String, FileDiffOutput> fileDiffs) {
+ List<String> r = new ArrayList<>(fileDiffs.size());
+ int linesInserted = 0;
+ int linesDeleted = 0;
+ for (String path : fileDiffs.keySet()) {
+ if (Patch.isMagic(path)) {
continue;
}
- switch (e.getChangeType()) {
+ FileDiffOutput fileDiff = fileDiffs.get(path);
+ linesInserted += fileDiff.insertions();
+ linesDeleted += fileDiff.deletions();
+ switch (fileDiff.changeType()) {
case ADDED:
case MODIFIED:
case DELETED:
case COPIED:
case REWRITE:
- r.add(e.getNewName());
+ r.add(
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType()));
break;
case RENAMED:
- r.add(e.getOldName());
- r.add(e.getNewName());
+ r.add(FilePathAdapter.getOldPath(fileDiff.oldPath(), fileDiff.changeType()));
+ r.add(
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType()));
break;
}
}
- return new DiffSummary(
- r.stream().sorted().toArray(String[]::new),
- patchList.getInsertions(),
- patchList.getDeletions());
+ return new DiffSummary(r.stream().sorted().toArray(String[]::new), linesInserted, linesDeleted);
}
}
diff --git a/java/com/google/gerrit/server/patch/FilePathAdapter.java b/java/com/google/gerrit/server/patch/FilePathAdapter.java
index ccd1466..2c98f1a 100644
--- a/java/com/google/gerrit/server/patch/FilePathAdapter.java
+++ b/java/com/google/gerrit/server/patch/FilePathAdapter.java
@@ -35,11 +35,12 @@
case DELETED:
case ADDED:
case MODIFIED:
- case REWRITE:
return null;
case COPIED:
case RENAMED:
return oldName.get();
+ case REWRITE:
+ return oldName.isPresent() ? oldName.get() : null;
default:
throw new IllegalArgumentException("Unsupported type " + changeType);
}
diff --git a/java/com/google/gerrit/server/patch/IntraLineLoader.java b/java/com/google/gerrit/server/patch/IntraLineLoader.java
index 29f5c2c..d6afa88 100644
--- a/java/com/google/gerrit/server/patch/IntraLineLoader.java
+++ b/java/com/google/gerrit/server/patch/IntraLineLoader.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.patch;
-import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -28,6 +27,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -35,6 +35,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.MyersDiff;
import org.eclipse.jgit.lib.Config;
@@ -273,39 +274,71 @@
* otherwise.
*/
private static boolean isValidTransformation(CharText lText, CharText rText, List<Edit> edits) {
- Supplier<String> applyDeleteAndReplaceEditsToLeft =
- () -> {
- StringBuilder reconstructed = toStringBuilder(lText);
- String right = toStringBuilder(rText).toString();
- // Process edits right to left to avoid re-computation of indices when characters are
- // removed.
- for (int i = edits.size() - 1; i >= 0; i--) {
- Edit edit = edits.get(i);
- if (edit.getType() == Edit.Type.REPLACE) {
- reconstructed.replace(
- edit.getBeginA(),
- edit.getEndA(),
- right.substring(edit.getBeginB(), edit.getEndB()));
- } else if (edit.getType() == Edit.Type.DELETE) {
- reconstructed.delete(edit.getBeginA(), edit.getEndA());
- }
- }
- return reconstructed.toString();
- };
- Supplier<StringBuilder> removeInsertEditsFromRight =
- () -> {
- StringBuilder reconstructed = toStringBuilder(rText);
- // Process edits right to left to avoid re-computation of indices when characters are
- // removed.
- for (int i = edits.size() - 1; i >= 0; i--) {
- Edit edit = edits.get(i);
- if (edit.getType() == Edit.Type.INSERT) {
- reconstructed.delete(edit.getBeginB(), edit.getEndB());
- }
- }
- return reconstructed;
- };
- return applyDeleteAndReplaceEditsToLeft.get().contentEquals(removeInsertEditsFromRight.get());
+ // Apply replace and delete edits to the left text
+ Optional<String> left =
+ applyEditsToString(
+ toStringBuilder(lText),
+ toStringBuilder(rText).toString(),
+ edits.stream()
+ .filter(e -> e.getType() == Edit.Type.REPLACE || e.getType() == Edit.Type.DELETE)
+ .collect(Collectors.toList()));
+ // Remove insert edits from the right text
+ Optional<String> right =
+ applyEditsToString(
+ toStringBuilder(rText),
+ null,
+ edits.stream()
+ .filter(e -> e.getType() == Edit.Type.INSERT)
+ .collect(Collectors.toList()));
+
+ return left.isPresent() && right.isPresent() && left.get().contentEquals(right.get());
+ }
+
+ /**
+ * Apply edits to the {@code target} string. Replace edits are applied to target and replaced with
+ * a substring from {@code from}. Delete edits are applied to target. Insert edits are removed
+ * from target.
+ *
+ * @return Optional containing the transformed string, or empty if the transformation fails (due
+ * to index out of bounds).
+ */
+ private static Optional<String> applyEditsToString(
+ StringBuilder target, String from, List<Edit> edits) {
+ // Process edits right to left to avoid re-computation of indices when characters are removed.
+ try {
+ for (int i = edits.size() - 1; i >= 0; i--) {
+ Edit edit = edits.get(i);
+ if (edit.getType() == Edit.Type.REPLACE) {
+ boundaryCheck(target, edit.getBeginA(), edit.getEndA() - 1);
+ boundaryCheck(from, edit.getBeginB(), edit.getEndB() - 1);
+ target.replace(
+ edit.getBeginA(), edit.getEndA(), from.substring(edit.getBeginB(), edit.getEndB()));
+ } else if (edit.getType() == Edit.Type.DELETE) {
+ boundaryCheck(target, edit.getBeginA(), edit.getEndA() - 1);
+ target.delete(edit.getBeginA(), edit.getEndA());
+ } else if (edit.getType() == Edit.Type.INSERT) {
+ boundaryCheck(target, edit.getBeginB(), edit.getEndB() - 1);
+ target.delete(edit.getBeginB(), edit.getEndB());
+ }
+ }
+ return Optional.of(target.toString());
+ } catch (StringIndexOutOfBoundsException unused) {
+ return Optional.empty();
+ }
+ }
+
+ private static void boundaryCheck(StringBuilder s, int i1, int i2) {
+ if (i1 >= 0 && i2 >= 0 && i1 < s.length() && i2 < s.length()) {
+ return;
+ }
+ throw new StringIndexOutOfBoundsException();
+ }
+
+ private static void boundaryCheck(String s, int i1, int i2) {
+ if (i1 >= 0 && i2 >= 0 && i1 < s.length() && i2 < s.length()) {
+ return;
+ }
+ throw new StringIndexOutOfBoundsException();
}
private static StringBuilder toStringBuilder(CharText text) {
diff --git a/java/com/google/gerrit/server/patch/PatchFile.java b/java/com/google/gerrit/server/patch/PatchFile.java
index ca5223d..81355cc 100644
--- a/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/java/com/google/gerrit/server/patch/PatchFile.java
@@ -18,7 +18,9 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.exceptions.NoSuchEntityException;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import java.io.IOException;
+import java.util.Map;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
@@ -35,7 +37,7 @@
/** State supporting processing of a single {@link Patch} instance. */
public class PatchFile {
private final Repository repo;
- private final PatchListEntry entry;
+ private final FileDiffOutput diff;
private final RevTree aTree;
private final RevTree bTree;
@@ -51,21 +53,30 @@
private Text a;
private Text b;
- public PatchFile(Repository repo, PatchList patchList, String fileName)
- throws MissingObjectException, IncorrectObjectTypeException, IOException {
+ public PatchFile(Repository repo, Map<String, FileDiffOutput> modifiedFiles, String fileName)
+ throws IOException {
this.repo = repo;
- this.entry = patchList.get(fileName);
+ this.diff =
+ modifiedFiles.values().stream()
+ .filter(f -> f.newPath().isPresent() && f.newPath().get().equals(fileName))
+ .findFirst()
+ .orElse(FileDiffOutput.empty(fileName, ObjectId.zeroId(), ObjectId.zeroId()));
+ if (Patch.PATCHSET_LEVEL.equals(fileName)) {
+ aTree = null;
+ bTree = null;
+ return;
+ }
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
- final RevCommit bCommit = rw.parseCommit(patchList.getNewId());
+ final RevCommit bCommit = rw.parseCommit(diff.newCommitId());
if (Patch.COMMIT_MSG.equals(fileName)) {
- if (patchList.getComparisonType().isAgainstParentOrAutoMerge()) {
+ if (diff.comparisonType().isAgainstParentOrAutoMerge()) {
a = Text.EMPTY;
} else {
// For the initial commit, we have an empty tree on Side A
- RevObject object = rw.parseAny(patchList.getOldId());
+ RevObject object = rw.parseAny(diff.oldCommitId());
a = object instanceof RevCommit ? Text.forCommit(reader, object) : Text.EMPTY;
}
b = Text.forCommit(reader, bCommit);
@@ -74,18 +85,18 @@
bTree = null;
} else if (Patch.MERGE_LIST.equals(fileName)) {
// For the initial commit, we have an empty tree on Side A
- RevObject object = rw.parseAny(patchList.getOldId());
+ RevObject object = rw.parseAny(diff.oldCommitId());
a =
object instanceof RevCommit
- ? Text.forMergeList(patchList.getComparisonType(), reader, object)
+ ? Text.forMergeList(diff.comparisonType(), reader, object)
: Text.EMPTY;
- b = Text.forMergeList(patchList.getComparisonType(), reader, bCommit);
+ b = Text.forMergeList(diff.comparisonType(), reader, bCommit);
aTree = null;
bTree = null;
} else {
- if (patchList.getOldId() != null) {
- aTree = rw.parseTree(patchList.getOldId());
+ if (diff.oldCommitId() != null) {
+ aTree = rw.parseTree(diff.oldCommitId());
} else {
final RevCommit p = bCommit.getParent(0);
rw.parseHeaders(p);
@@ -97,11 +108,11 @@
}
private String getOldName() {
- String name = entry.getOldName();
+ String name = FilePathAdapter.getOldPath(diff.oldPath(), diff.changeType());
if (name != null) {
return name;
}
- return entry.getNewName();
+ return FilePathAdapter.getNewPath(diff.oldPath(), diff.newPath(), diff.changeType());
}
/**
@@ -111,7 +122,6 @@
* @param line the line number to extract (1 based; 1 is the first line).
* @return the string version of the file line.
* @throws IOException the patch or complete file content cannot be read.
- * @throws NoSuchEntityException
*/
public String getLine(int file, int line) throws IOException, NoSuchEntityException {
switch (file) {
@@ -123,7 +133,10 @@
case 1:
if (b == null) {
- b = load(bTree, entry.getNewName());
+ b =
+ load(
+ bTree,
+ FilePathAdapter.getNewPath(diff.oldPath(), diff.newPath(), diff.changeType()));
}
return b.getString(line - 1);
@@ -135,7 +148,7 @@
private Text load(ObjectId tree, String path)
throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
IOException {
- if (path == null) {
+ if (path == null || Patch.PATCHSET_LEVEL.equals(path)) {
return Text.EMPTY;
}
final TreeWalk tw = TreeWalk.forPath(repo, path, tree);
diff --git a/java/com/google/gerrit/server/patch/PatchList.java b/java/com/google/gerrit/server/patch/PatchList.java
index cb95553..b983fb8 100644
--- a/java/com/google/gerrit/server/patch/PatchList.java
+++ b/java/com/google/gerrit/server/patch/PatchList.java
@@ -140,17 +140,17 @@
return Collections.unmodifiableList(Arrays.asList(patches));
}
- /** @return the comparison type */
+ /** Returns the comparison type */
public ComparisonType getComparisonType() {
return comparisonType;
}
- /** @return total number of new lines added. */
+ /** Returns total number of new lines added. */
public int getInsertions() {
return insertions;
}
- /** @return total number of lines removed. */
+ /** Returns total number of lines removed. */
public int getDeletions() {
return deletions;
}
diff --git a/java/com/google/gerrit/server/patch/PatchListCache.java b/java/com/google/gerrit/server/patch/PatchListCache.java
index e60302a..6d42249 100644
--- a/java/com/google/gerrit/server/patch/PatchListCache.java
+++ b/java/com/google/gerrit/server/patch/PatchListCache.java
@@ -14,10 +14,7 @@
package com.google.gerrit.server.patch;
-import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
-import org.eclipse.jgit.lib.ObjectId;
/** Provides a cached list of {@link PatchListEntry}. */
public interface PatchListCache {
@@ -32,30 +29,6 @@
@Deprecated
PatchList get(PatchListKey key, Project.NameKey project) throws PatchListNotAvailableException;
- /**
- * Returns the patch list - list of modified files - between two commits.
- *
- * @param change entity containing all change data.
- * @param patchSet single revision of a {@link Change}.
- * @return patch list containing the modified files between two commits.
- * @deprecated use {@link DiffOperations} instead.
- */
- @Deprecated
- PatchList get(Change change, PatchSet patchSet) throws PatchListNotAvailableException;
-
- /**
- * Returns the patch list - list of modified files - between two commits.
- *
- * @param change entity containing all change data.
- * @param patchSet single revision of a {@link Change}.
- * @param parentNum 1-based parent number when new commit used in comparison is a merge commit.
- * @return patch list containing the modified files between two commits.
- * @deprecated use {@link DiffOperations} instead.
- */
- @Deprecated
- ObjectId getOldId(Change change, PatchSet patchSet, Integer parentNum)
- throws PatchListNotAvailableException;
-
IntraLineDiff getIntraLineDiff(IntraLineDiffKey key, IntraLineDiffArgs args);
DiffSummary getDiffSummary(DiffSummaryKey key, Project.NameKey project)
diff --git a/java/com/google/gerrit/server/patch/PatchListCacheImpl.java b/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
index a3e9a54..dd2bb47 100644
--- a/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
@@ -18,10 +18,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.cache.Cache;
import com.google.common.util.concurrent.UncheckedExecutionException;
-import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.cache.CacheBackend;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -125,27 +122,6 @@
}
@Override
- public PatchList get(Change change, PatchSet patchSet) throws PatchListNotAvailableException {
- return get(change, patchSet, null);
- }
-
- @Override
- public ObjectId getOldId(Change change, PatchSet patchSet, Integer parentNum)
- throws PatchListNotAvailableException {
- return get(change, patchSet, parentNum).getOldId();
- }
-
- private PatchList get(Change change, PatchSet patchSet, Integer parentNum)
- throws PatchListNotAvailableException {
- Project.NameKey project = change.getProject();
- ObjectId b = patchSet.commitId();
- if (parentNum != null) {
- return get(PatchListKey.againstParentNum(parentNum, b, Whitespace.IGNORE_NONE), project);
- }
- return get(PatchListKey.againstDefaultBase(b, Whitespace.IGNORE_NONE), project);
- }
-
- @Override
public IntraLineDiff getIntraLineDiff(IntraLineDiffKey key, IntraLineDiffArgs args) {
if (computeIntraline) {
try {
diff --git a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
index 5998bba..0b08c4f 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptBuilder.java
@@ -235,10 +235,10 @@
return null;
case DELETED:
case MODIFIED:
- case REWRITE:
return entry.getNewName();
case COPIED:
case RENAMED:
+ case REWRITE:
default:
return entry.getOldName();
}
diff --git a/java/com/google/gerrit/server/patch/PatchScriptFactory.java b/java/com/google/gerrit/server/patch/PatchScriptFactory.java
index fbb6559..96b23c8 100644
--- a/java/com/google/gerrit/server/patch/PatchScriptFactory.java
+++ b/java/com/google/gerrit/server/patch/PatchScriptFactory.java
@@ -26,20 +26,13 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.client.DiffPreferencesInfo;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.metrics.Counter1;
-import com.google.gerrit.metrics.Description;
-import com.google.gerrit.metrics.Field;
-import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.PatchSetUtil;
-import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.edit.ChangeEdit;
import com.google.gerrit.server.edit.ChangeEditUtil;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LargeObjectException;
-import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.patch.PatchScriptBuilder.IntraLineDiffCalculatorResult;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
@@ -50,23 +43,15 @@
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
-import com.google.inject.Inject;
import com.google.inject.Provider;
-import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang.exception.ExceptionUtils;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
-import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
@@ -93,33 +78,10 @@
CurrentUser currentUser);
}
- /** These metrics are temporary for launching the new redesigned diff cache. */
- @Singleton
- static class Metrics {
- final Counter1<String> diffs;
- static final String MATCH = "match";
- static final String MISMATCH = "mismatch";
- static final String ERROR = "error";
-
- @Inject
- Metrics(MetricMaker metricMaker) {
- diffs =
- metricMaker.newCounter(
- "diff/get_diff/dark_launch",
- new Description(
- "Total number of matching, non-matching, or error in diffs in the old and new diff cache implementations.")
- .setRate()
- .setUnit("count"),
- Field.ofString("type", Metadata.Builder::eventType).build());
- }
- }
-
private final GitRepositoryManager repoManager;
private final PatchSetUtil psUtil;
private final Provider<PatchScriptBuilder> builderFactory;
private final PatchListCache patchListCache;
- private final Metrics metrics;
- private final ExecutorService executor;
private final String fileName;
@Nullable private final PatchSet.Id psa;
@@ -137,8 +99,6 @@
private ChangeNotes notes;
- private final boolean runNewDiffCache;
-
@AssistedInject
PatchScriptFactory(
GitRepositoryManager grm,
@@ -149,9 +109,6 @@
PermissionBackend permissionBackend,
ProjectCache projectCache,
DiffOperations diffOperations,
- Metrics metrics,
- @DiffExecutor ExecutorService executor,
- @GerritServerConfig Config cfg,
@Assisted ChangeNotes notes,
@Assisted String fileName,
@Assisted("patchSetA") @Nullable PatchSet.Id patchSetA,
@@ -167,8 +124,6 @@
this.permissionBackend = permissionBackend;
this.projectCache = projectCache;
this.diffOperations = diffOperations;
- this.metrics = metrics;
- this.executor = executor;
this.fileName = fileName;
this.psa = patchSetA;
@@ -176,9 +131,6 @@
this.psb = patchSetB;
this.diffPrefs = diffPrefs;
this.currentUser = currentUser;
-
- this.runNewDiffCache = cfg.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
-
changeId = patchSetB.changeId();
}
@@ -192,9 +144,6 @@
PermissionBackend permissionBackend,
ProjectCache projectCache,
DiffOperations diffOperations,
- Metrics metrics,
- @DiffExecutor ExecutorService executor,
- @GerritServerConfig Config cfg,
@Assisted ChangeNotes notes,
@Assisted String fileName,
@Assisted int parentNum,
@@ -210,8 +159,6 @@
this.permissionBackend = permissionBackend;
this.projectCache = projectCache;
this.diffOperations = diffOperations;
- this.metrics = metrics;
- this.executor = executor;
this.fileName = fileName;
this.psa = null;
@@ -219,9 +166,6 @@
this.psb = patchSetB;
this.diffPrefs = diffPrefs;
this.currentUser = currentUser;
-
- this.runNewDiffCache = cfg.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
-
changeId = patchSetB.changeId();
checkArgument(parentNum > 0, "parentNum must be > 0");
}
@@ -259,16 +203,7 @@
}
bId = edit.get().getEditCommit();
}
- if (runNewDiffCache) {
- PatchScript patchScript = getPatchScriptWithNewDiffCache(git, aId, bId);
- // TODO(ghareeb): remove the async run. This is temporarily used to keep sanity checking
- // the results while rolling out the new diff cache.
- runOldDiffCacheAsyncAndExportMetrics(git, aId, bId, patchScript);
- return patchScript;
- }
- return getPatchScriptWithOldDiffCache(git, aId, bId);
- } catch (PatchListNotAvailableException e) {
- throw new NoSuchChangeException(changeId, e);
+ return getPatchScript(git, aId, bId);
} catch (DiffNotAvailableException e) {
throw new StorageException(e);
} catch (IOException e) {
@@ -286,42 +221,7 @@
}
}
- private void runOldDiffCacheAsyncAndExportMetrics(
- Repository git, ObjectId aId, ObjectId bId, PatchScript expected) {
- @SuppressWarnings("unused")
- Future<?> possiblyIgnoredError =
- executor.submit(
- () -> {
- try {
- PatchScript patchScript = getPatchScriptWithOldDiffCache(git, aId, bId);
- if (areEqualPatchscripts(patchScript, expected)) {
- metrics.diffs.increment(Metrics.MATCH);
- } else {
- metrics.diffs.increment(Metrics.MISMATCH);
- logger.atWarning().atMostEvery(10, TimeUnit.SECONDS).log(
- "Mismatching diff for change %s, old commit ID: %s, new commit ID: %s, file name: %s.",
- changeId.toString(), aId, bId, fileName);
- }
- } catch (PatchListNotAvailableException | IOException e) {
- metrics.diffs.increment(Metrics.ERROR);
- logger.atSevere().atMostEvery(10, TimeUnit.SECONDS).log(
- String.format(
- "Error computing new diff for change %s, old commit ID: %s, new commit ID: %s.\n",
- changeId.toString(), aId, bId)
- + ExceptionUtils.getStackTrace(e));
- }
- });
- }
-
- private PatchScript getPatchScriptWithOldDiffCache(Repository git, ObjectId aId, ObjectId bId)
- throws IOException, PatchListNotAvailableException {
- PatchScriptBuilder patchScriptBuilder = newBuilder();
- PatchList list = listFor(keyFor(aId, bId, diffPrefs.ignoreWhitespace));
- PatchListEntry content = list.get(fileName);
- return patchScriptBuilder.toPatchScriptOld(git, list, content);
- }
-
- private PatchScript getPatchScriptWithNewDiffCache(Repository git, ObjectId aId, ObjectId bId)
+ private PatchScript getPatchScript(Repository git, ObjectId aId, ObjectId bId)
throws IOException, DiffNotAvailableException {
FileDiffOutput fileDiffOutput =
aId == null
@@ -332,61 +232,6 @@
return newBuilder().toPatchScriptNew(git, fileDiffOutput);
}
- /**
- * The comparison is not exhaustive but is using the most important fields. Comparing all fields
- * will require some work in {@link PatchScript} to, e.g., convert it to autovalue. This
- * comparison method shall give a strong signal that both patchscripts are almost identical.
- */
- private static boolean areEqualPatchscripts(PatchScript ps1, PatchScript ps2) {
- boolean equal = true;
- if (!ps1.getChangeType().equals(ps2.getChangeType())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching change type: old = %s, new = %s.", ps1.getChangeType(), ps2.getChangeType());
- }
- if (!ps1.getPatchHeader().equals(ps2.getPatchHeader())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching patch header: old = %s, new = %s.",
- ps1.getPatchHeader(), ps2.getPatchHeader());
- }
- if (!Objects.equals(ps1.getOldName(), ps2.getOldName())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching old name: old = %s, new = %s.", ps1.getOldName(), ps2.getOldName());
- }
- if (!Objects.equals(ps1.getNewName(), ps2.getNewName())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching new name: old = %s, new = %s.", ps1.getNewName(), ps2.getNewName());
- }
- if (!ps1.getEdits().containsAll(ps2.getEdits())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching edits: old = %s, new = %s.", ps1.getEdits(), ps2.getEdits());
- }
- if (!ps2.getEdits().containsAll(ps1.getEdits())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching edits: old = %s, new = %s.", ps1.getEdits(), ps2.getEdits());
- }
- if (!ps1.getEditsDueToRebase().equals(ps2.getEditsDueToRebase())) {
- equal = false;
- logger.atWarning().log(
- "Mismatching edits due to rebase: old = %s, new = %s.",
- ps1.getEditsDueToRebase(), ps2.getEditsDueToRebase());
- }
- if (!ps1.getA().equals(ps2.getA())) {
- equal = false;
- logger.atWarning().log("Mismatching sparse file content in old commit.");
- }
- if (!ps1.getB().equals(ps2.getB())) {
- equal = false;
- logger.atWarning().log("Mismatching sparse file content in new commit.");
- }
- return equal;
- }
-
private Optional<ObjectId> getAId() {
if (psa == null) {
return Optional.empty();
@@ -404,17 +249,6 @@
return Optional.of(getCommitId(psb));
}
- private PatchListKey keyFor(ObjectId aId, ObjectId bId, Whitespace whitespace) {
- if (parentNum == 0) {
- return PatchListKey.againstCommit(aId, bId, whitespace);
- }
- return PatchListKey.againstParentNum(parentNum, bId, whitespace);
- }
-
- private PatchList listFor(PatchListKey key) throws PatchListNotAvailableException {
- return patchListCache.get(key, notes.getProjectName());
- }
-
private PatchScriptBuilder newBuilder() {
final PatchScriptBuilder b = builderFactory.get();
b.setDiffPrefs(diffPrefs);
diff --git a/java/com/google/gerrit/server/patch/SubmitWithStickyApprovalDiff.java b/java/com/google/gerrit/server/patch/SubmitWithStickyApprovalDiff.java
index 62387ee..572d73d 100644
--- a/java/com/google/gerrit/server/patch/SubmitWithStickyApprovalDiff.java
+++ b/java/com/google/gerrit/server/patch/SubmitWithStickyApprovalDiff.java
@@ -16,6 +16,7 @@
import static com.google.gerrit.server.project.ProjectCache.illegalState;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.PatchScript;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.LabelType;
@@ -51,7 +52,6 @@
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.TemporaryBuffer;
@@ -128,11 +128,39 @@
}
diff.append("The change was submitted with unreviewed changes in the following files:\n\n");
-
- for (FileDiffOutput fileDiff : modifiedFilesList) {
- diff.append(
- getDiffForFile(
- notes, currentPatchset.id(), latestApprovedPatchsetId, fileDiff, currentUser));
+ TemporaryBuffer.Heap buffer =
+ new TemporaryBuffer.Heap(Math.min(HEAP_EST_SIZE, maxCumulativeSize), maxCumulativeSize);
+ try (Repository repository = repositoryManager.openRepository(notes.getProjectName());
+ DiffFormatter formatter = new DiffFormatter(buffer)) {
+ formatter.setRepository(repository);
+ formatter.setDetectRenames(true);
+ boolean isDiffTooLarge = false;
+ List<String> formatterResult = null;
+ try {
+ formatter.format(
+ modifiedFilesList.get(0).oldCommitId(), modifiedFilesList.get(0).newCommitId());
+ // This returns the diff for all the files.
+ formatterResult =
+ Arrays.stream(RawParseUtils.decode(buffer.toByteArray()).split("\n"))
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ if (JGitText.get().inMemoryBufferLimitExceeded.equals(e.getMessage())) {
+ isDiffTooLarge = true;
+ } else {
+ throw e;
+ }
+ }
+ for (FileDiffOutput fileDiff : modifiedFilesList) {
+ diff.append(
+ getDiffForFile(
+ notes,
+ currentPatchset.id(),
+ latestApprovedPatchsetId,
+ fileDiff,
+ currentUser,
+ formatterResult,
+ isDiffTooLarge));
+ }
}
return diff.toString();
}
@@ -142,7 +170,9 @@
PatchSet.Id currentPatchsetId,
PatchSet.Id latestApprovedPatchsetId,
FileDiffOutput fileDiffOutput,
- CurrentUser currentUser)
+ CurrentUser currentUser,
+ @Nullable List<String> formatterResult,
+ boolean isDiffTooLarge)
throws AuthException, InvalidChangeOperationException, IOException,
PermissionBackendException {
StringBuilder diff =
@@ -167,6 +197,7 @@
currentUser);
PatchScript patchScript = null;
try {
+ // TODO(paiking): we can get rid of this call to optimize by checking the diff for renames.
patchScript = patchScriptFactory.call();
} catch (LargeObjectException exception) {
diff.append("The file content is too large for showing the full diff. \n\n");
@@ -178,7 +209,15 @@
"The file %s was renamed to %s\n",
fileDiffOutput.oldPath().get(), fileDiffOutput.newPath().get()));
}
- diff.append(getUnifiedDiff(patchScript, notes));
+ if (isDiffTooLarge) {
+ diff.append("The diff is too large to show. Please review the diff.");
+ diff.append("\n```\n");
+ return diff.toString();
+ }
+ // This filters only the file we need.
+ // TODO(paiking): we can make this more efficient by mapping the files to their respective
+ // diffs prior to this method, such that we need to go over the diff only once.
+ diff.append(getDiffForFile(patchScript, formatterResult));
// This line (and the ``` above) are useful for formatting in the web UI.
diff.append("\n```\n");
return diff.toString();
@@ -188,63 +227,42 @@
* Show patch set as unified difference for a specific file. We on purpose are not using {@link
* DiffInfoCreator} since we'd like to get the original git/JGit style diff.
*/
- public String getUnifiedDiff(PatchScript patchScript, ChangeNotes changeNotes)
- throws IOException {
- TemporaryBuffer.Heap buf =
- new TemporaryBuffer.Heap(Math.min(HEAP_EST_SIZE, maxCumulativeSize), maxCumulativeSize);
- try (DiffFormatter fmt = new DiffFormatter(buf);
- // TODO(paiking): ensure we open the repository only once by opening it in the calling
- // method.
- Repository git = repositoryManager.openRepository(changeNotes.getProjectName())) {
- fmt.setRepository(git);
- fmt.setDetectRenames(true);
- fmt.format(
- ObjectId.fromString(patchScript.getFileInfoA().commitId),
- ObjectId.fromString(patchScript.getFileInfoB().commitId));
- List<String> formatterResult =
- Arrays.stream(RawParseUtils.decode(buf.toByteArray()).split("\n"))
- .collect(Collectors.toList());
- // only return information about the current file, and not about files that are not
- // relevant. DiffFormatter returns other potential files because of rebases, which we can
- // ignore.
- List<String> modifiedFormatterResult = new ArrayList<>();
- int indexOfFormatterResult = 0;
- while (formatterResult.size() > indexOfFormatterResult
- && !formatterResult
- .get(indexOfFormatterResult)
- .equals(
- String.format(
- "diff --git a/%s b/%s",
- patchScript.getOldName() != null
- ? patchScript.getOldName()
- : patchScript.getNewName(),
- patchScript.getNewName()))) {
- indexOfFormatterResult++;
- }
- // remove non user friendly information.
- while (formatterResult.size() > indexOfFormatterResult
- && !formatterResult.get(indexOfFormatterResult).startsWith("@@")) {
- indexOfFormatterResult++;
- }
- for (; indexOfFormatterResult < formatterResult.size(); indexOfFormatterResult++) {
- if (formatterResult.get(indexOfFormatterResult).startsWith("diff --git")) {
- break;
- }
- modifiedFormatterResult.add(formatterResult.get(indexOfFormatterResult));
- }
- if (modifiedFormatterResult.size() == 0) {
- // This happens for diffs that are just renames, but we already account for renames.
- return "";
- }
- return modifiedFormatterResult.stream()
- .filter(s -> !s.equals("\\ No newline at end of file"))
- .collect(Collectors.joining("\n"));
- } catch (IOException e) {
- if (JGitText.get().inMemoryBufferLimitExceeded.equals(e.getMessage())) {
- return "The diff is too large to show. Please review the diff.";
- }
- throw e;
+ public String getDiffForFile(PatchScript patchScript, List<String> formatterResult) {
+ // only return information about the current file, and not about files that are not
+ // relevant. DiffFormatter returns other potential files because of rebases, which we can
+ // ignore.
+ List<String> modifiedFormatterResult = new ArrayList<>();
+ int indexOfFormatterResult = 0;
+ while (formatterResult.size() > indexOfFormatterResult
+ && !formatterResult
+ .get(indexOfFormatterResult)
+ .equals(
+ String.format(
+ "diff --git a/%s b/%s",
+ patchScript.getOldName() != null
+ ? patchScript.getOldName()
+ : patchScript.getNewName(),
+ patchScript.getNewName()))) {
+ indexOfFormatterResult++;
}
+ // remove non user friendly information.
+ while (formatterResult.size() > indexOfFormatterResult
+ && !formatterResult.get(indexOfFormatterResult).startsWith("@@")) {
+ indexOfFormatterResult++;
+ }
+ for (; indexOfFormatterResult < formatterResult.size(); indexOfFormatterResult++) {
+ if (formatterResult.get(indexOfFormatterResult).startsWith("diff --git")) {
+ break;
+ }
+ modifiedFormatterResult.add(formatterResult.get(indexOfFormatterResult));
+ }
+ if (modifiedFormatterResult.size() == 0) {
+ // This happens for diffs that are just renames, but we already account for renames.
+ return "";
+ }
+ return modifiedFormatterResult.stream()
+ .filter(s -> !s.equals("\\ No newline at end of file"))
+ .collect(Collectors.joining("\n"));
}
private DiffPreferencesInfo createDefaultDiffPreferencesInfo() {
diff --git a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCache.java b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCache.java
index 56f49c9..76d1710 100644
--- a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCache.java
+++ b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCache.java
@@ -35,9 +35,10 @@
public interface ModifiedFilesCache {
/**
+ * Returns the list of {@link ModifiedFile}s between the 2 git commits identified by the key
+ *
* @param key used to identify two git commits and contains other attributes to control the diff
* calculation.
- * @return the list of {@link ModifiedFile}s between the 2 git commits identified by the key.
* @throws DiffNotAvailableException the supplied commits IDs of the key do no exist, are not IDs
* of a commit, or an exception occurred while reading a pack file.
*/
diff --git a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
index e4fd728..460c2e2 100644
--- a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheImpl.java
@@ -86,7 +86,7 @@
.valueSerializer(GitModifiedFilesCacheImpl.ValueSerializer.INSTANCE)
.maximumWeight(10 << 20)
.weigher(ModifiedFilesWeigher.class)
- .version(2)
+ .version(3)
.loader(ModifiedFilesLoader.class);
}
};
@@ -208,27 +208,22 @@
}
/**
- * Return the {@code modifiedFiles} input list while merging {@link ChangeType#ADDED} and {@link
- * ChangeType#DELETED} entries for the same file into a single {@link ChangeType#REWRITE} entry.
+ * Return the {@code modifiedFiles} input list while merging rewritten entries.
*
- * <p>Background: In some cases, JGit returns two diff entries (ADDED + DELETED) for the same
- * file path. This happens e.g. when a file's mode is changed between patchsets, for example
- * converting a symlink file to a regular file. We identify this case and return a single
- * modified file with changeType = {@link ChangeType#REWRITE}.
+ * <p>Background: In some cases, JGit returns two diff entries (ADDED/DELETED, RENAMED/DELETED,
+ * etc...) for the same file path. This happens e.g. when a file's mode is changed between
+ * patchsets, for example converting a symlink file to a regular file. We identify this case and
+ * return a single modified file with changeType = {@link ChangeType#REWRITE}.
*/
private static List<ModifiedFile> mergeRewrittenEntries(List<ModifiedFile> modifiedFiles) {
List<ModifiedFile> result = new ArrayList<>();
-
- // Handle ADDED and DELETED entries separately.
ListMultimap<String, ModifiedFile> byPath = ArrayListMultimap.create();
modifiedFiles.stream()
- .filter(ModifiedFilesLoader::isAddedOrDeleted)
.forEach(
f -> {
- if (f.oldPath().isPresent()) {
+ if (f.changeType() == ChangeType.DELETED) {
byPath.get(f.oldPath().get()).add(f);
- }
- if (f.newPath().isPresent()) {
+ } else {
byPath.get(f.newPath().get()).add(f);
}
});
@@ -236,31 +231,12 @@
List<ModifiedFile> entries = byPath.get(path);
if (entries.size() == 1) {
result.add(entries.get(0));
- } else if (entries.size() == 2) {
- result.add(getAddedEntry(entries).toBuilder().changeType(ChangeType.REWRITE).build());
} else {
- // JGit error. Not expected to happen.
- logger.atWarning().log(
- "Found %d ADDED and DELETED entries for the same file path: %s."
- + " Adding the first entry only to the result.",
- entries.size(), entries);
- result.add(entries.get(0));
+ // More than one. Return a single REWRITE entry.
+ result.add(entries.get(0).toBuilder().changeType(ChangeType.REWRITE).build());
}
}
-
- // Add the remaining non ADDED/DELETED entries to the result
- modifiedFiles.stream().filter(f -> !isAddedOrDeleted(f)).forEach(result::add);
return result;
}
-
- private static boolean isAddedOrDeleted(ModifiedFile f) {
- return f.changeType() == ChangeType.ADDED || f.changeType() == ChangeType.DELETED;
- }
-
- private static ModifiedFile getAddedEntry(List<ModifiedFile> modifiedFiles) {
- return modifiedFiles.get(0).changeType() == ChangeType.ADDED
- ? modifiedFiles.get(0)
- : modifiedFiles.get(1);
- }
}
}
diff --git a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheKey.java b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheKey.java
index 2ac3f5e..4a406c8 100644
--- a/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheKey.java
+++ b/java/com/google/gerrit/server/patch/diff/ModifiedFilesCacheKey.java
@@ -32,10 +32,10 @@
/** A specific git project / repository. */
public abstract Project.NameKey project();
- /** @return the old commit ID used in the git tree diff */
+ /** Returns the old commit ID used in the git tree diff */
public abstract ObjectId aCommit();
- /** @return the new commit ID used in the git tree diff */
+ /** Returns the new commit ID used in the git tree diff */
public abstract ObjectId bCommit();
/**
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
index a67f221..92c3b39 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffCacheImpl.java
@@ -97,7 +97,7 @@
persist(DIFF, FileDiffCacheKey.class, FileDiffOutput.class)
.maximumWeight(10 << 20)
.weigher(FileDiffWeigher.class)
- .version(7)
+ .version(8)
.keySerializer(FileDiffCacheKey.Serializer.INSTANCE)
.valueSerializer(FileDiffOutput.Serializer.INSTANCE)
.loader(FileDiffLoader.class);
diff --git a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
index 3c6d746..242c1a4 100644
--- a/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
+++ b/java/com/google/gerrit/server/patch/filediff/FileDiffOutput.java
@@ -37,7 +37,10 @@
public abstract class FileDiffOutput implements Serializable {
private static final long serialVersionUID = 1L;
- /** The 20 bytes SHA-1 object ID of the old git commit used in the diff. */
+ /**
+ * The 20 bytes SHA-1 object ID of the old git commit used in the diff, or {@link
+ * ObjectId#zeroId()} if {@link #newCommitId()} was a root commit.
+ */
public abstract ObjectId oldCommitId();
/** The 20 bytes SHA-1 object ID of the new git commit used in the diff. */
@@ -130,9 +133,16 @@
.build();
}
+ /**
+ * Create a negative file diff. We use this to cache negative diffs for entries that result in
+ * timeouts.
+ */
public static FileDiffOutput createNegative(
String filePath, ObjectId oldCommitId, ObjectId newCommitId) {
- return empty(filePath, oldCommitId, newCommitId).toBuilder().build();
+ return empty(filePath, oldCommitId, newCommitId)
+ .toBuilder()
+ .negative(Optional.of(true))
+ .build();
}
/** Returns true if this entity represents an unchanged file between two commits. */
diff --git a/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java b/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
index 017e276..031f3db 100644
--- a/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
+++ b/java/com/google/gerrit/server/patch/filediff/PatchListLoader.java
@@ -35,6 +35,9 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -52,6 +55,7 @@
import com.google.gerrit.server.patch.Text;
import com.google.gerrit.server.patch.filediff.EditTransformer.ContextAwareEdit;
import com.google.inject.Inject;
+import com.google.inject.Singleton;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.ArrayList;
@@ -99,12 +103,30 @@
PatchListLoader create(PatchListKey key, Project.NameKey project);
}
+ @Singleton
+ static class Metrics {
+ final Counter0 timeouts;
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ // TODO(ghareeb): Remove this metric from documentation once this class is deprecated.
+ timeouts =
+ metricMaker.newCounter(
+ "caches/diff/legacy/timeouts",
+ new Description(
+ "Total number of git file diff computations that resulted in timeouts.")
+ .setRate()
+ .setUnit("count"));
+ }
+ }
+
private final GitRepositoryManager repoManager;
private final PatchListCache patchListCache;
private final ThreeWayMergeStrategy mergeStrategy;
private final ExecutorService diffExecutor;
private final AutoMerger autoMerger;
private final PatchListKey key;
+ private final Metrics metrics;
private final Project.NameKey project;
private final long timeoutMillis;
@@ -115,16 +137,18 @@
@GerritServerConfig Config cfg,
@DiffExecutor ExecutorService de,
AutoMerger am,
+ Metrics metrics,
@Assisted PatchListKey k,
@Assisted Project.NameKey p) {
- repoManager = mgr;
- patchListCache = plc;
- mergeStrategy = MergeUtil.getMergeStrategy(cfg);
- diffExecutor = de;
- autoMerger = am;
- key = k;
- project = p;
- timeoutMillis =
+ this.repoManager = mgr;
+ this.patchListCache = plc;
+ this.mergeStrategy = MergeUtil.getMergeStrategy(cfg);
+ this.diffExecutor = de;
+ this.autoMerger = am;
+ this.metrics = metrics;
+ this.key = k;
+ this.project = p;
+ this.timeoutMillis =
ConfigUtil.getTimeUnit(
cfg,
"cache",
@@ -529,6 +553,7 @@
try {
return result.get(timeoutMillis, TimeUnit.MILLISECONDS);
} catch (InterruptedException | TimeoutException e) {
+ metrics.timeouts.increment();
logger.atWarning().log(
"%s ms timeout reached for Diff loader in project %s"
+ " on commit %s on path %s comparing %s..%s",
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
index a502a46..2f23c8c 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiff.java
@@ -34,6 +34,7 @@
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.patch.FileHeader;
/**
@@ -120,7 +121,10 @@
/** The file name at the new git tree identified by {@link #newId()} */
public abstract Optional<String> newPath();
- /** The 20 bytes SHA-1 object ID of the old git tree of the diff. */
+ /**
+ * The 20 bytes SHA-1 object ID of the old git tree of the diff, or {@link ObjectId#zeroId()} if
+ * {@link #newId()} was a root git tree (i.e. has no parents).
+ */
public abstract AbbreviatedObjectId oldId();
/** The 20 bytes SHA-1 object ID of the new git tree of the diff. */
diff --git a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
index 77b8938..f293a64 100644
--- a/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
+++ b/java/com/google/gerrit/server/patch/gitfilediff/GitFileDiffCacheImpl.java
@@ -31,6 +31,9 @@
import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -47,6 +50,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -91,6 +95,22 @@
};
}
+ @Singleton
+ static class Metrics {
+ final Counter0 timeouts;
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ timeouts =
+ metricMaker.newCounter(
+ "caches/diff/timeouts",
+ new Description(
+ "Total number of git file diff computations that resulted in timeouts.")
+ .setRate()
+ .setUnit("count"));
+ }
+ }
+
/** Enum for the supported diff algorithms for the file diff computation. */
public enum DiffAlgorithm {
HISTOGRAM_WITH_FALLBACK_MYERS,
@@ -110,9 +130,6 @@
private final LoadingCache<GitFileDiffCacheKey, GitFileDiff> cache;
- private static final ImmutableSet<Patch.ChangeType> ADDED_AND_DELETED =
- ImmutableSet.of(Patch.ChangeType.ADDED, Patch.ChangeType.DELETED);
-
@Inject
public GitFileDiffCacheImpl(
@Named(GIT_DIFF) LoadingCache<GitFileDiffCacheKey, GitFileDiff> cache) {
@@ -152,12 +169,14 @@
private final GitRepositoryManager repoManager;
private final ExecutorService diffExecutor;
private final long timeoutMillis;
+ private final Metrics metrics;
@Inject
public Loader(
@GerritServerConfig Config cfg,
GitRepositoryManager repoManager,
- @DiffExecutor ExecutorService de) {
+ @DiffExecutor ExecutorService de,
+ Metrics metrics) {
this.repoManager = repoManager;
this.diffExecutor = de;
this.timeoutMillis =
@@ -168,6 +187,7 @@
"timeout",
TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS),
TimeUnit.MILLISECONDS);
+ this.metrics = metrics;
}
@Override
@@ -346,6 +366,7 @@
return GitFileDiff.create(diffEntry, fileHeader);
} catch (InterruptedException | TimeoutException e) {
// If timeout happens, create a negative result
+ metrics.timeouts.increment();
return GitFileDiff.createNegative(
AbbreviatedObjectId.fromObjectId(key.oldTree()),
AbbreviatedObjectId.fromObjectId(key.newTree()),
@@ -360,12 +381,13 @@
}
/**
- * Create a single {@link GitFileDiff} with {@link Patch.ChangeType} equals {@link
- * Patch.ChangeType#REWRITE}, assuming the input list contains two entries with types {@link
- * Patch.ChangeType#ADDED} and {@link Patch.ChangeType#DELETED}.
+ * Create a single {@link GitFileDiff} with {@link com.google.gerrit.entities.Patch.ChangeType}
+ * equals {@link com.google.gerrit.entities.Patch.ChangeType#REWRITE}, assuming the input list
+ * contains two entries.
*
* @param gitDiffs input list of exactly two {@link GitFileDiff} for same file path.
- * @return a single {@link GitFileDiff} with change type equals {@link Patch.ChangeType#REWRITE}.
+ * @return a single {@link GitFileDiff} with change type equals {@link
+ * com.google.gerrit.entities.Patch.ChangeType#REWRITE}.
* @throws DiffNotAvailableException if input list contains git diffs with change types other than
* {ADDED, DELETED}. This is a JGit error.
*/
@@ -377,19 +399,9 @@
"JGit error: found %d dff entries for same file path %s",
gitDiffs.size(), gitDiffs.get(0).getDefaultPath()));
}
- if (!ImmutableSet.of(gitDiffs.get(0).changeType(), gitDiffs.get(1).changeType())
- .equals(ADDED_AND_DELETED)) {
- // This is an illegal state. JGit is not supposed to return this, so we throw an exception.
- throw new DiffNotAvailableException(
- String.format(
- "JGit error: unexpected change types %s and %s for same file path %s",
- gitDiffs.get(0).changeType(),
- gitDiffs.get(1).changeType(),
- gitDiffs.get(0).getDefaultPath()));
- }
- GitFileDiff addedEntry =
- gitDiffs.get(0).changeType() == Patch.ChangeType.ADDED ? gitDiffs.get(0) : gitDiffs.get(1);
- return addedEntry.toBuilder().changeType(Patch.ChangeType.REWRITE).build();
+ // Convert the first entry (prioritized according to change type enum order) to REWRITE
+ gitDiffs.sort(Comparator.comparingInt(o -> o.changeType().ordinal()));
+ return gitDiffs.get(0).toBuilder().changeType(Patch.ChangeType.REWRITE).build();
}
/** An entity representing the options affecting the diff computation. */
diff --git a/java/com/google/gerrit/server/permissions/LabelPermission.java b/java/com/google/gerrit/server/permissions/LabelPermission.java
index 268570c..c266caa 100644
--- a/java/com/google/gerrit/server/permissions/LabelPermission.java
+++ b/java/com/google/gerrit/server/permissions/LabelPermission.java
@@ -71,12 +71,12 @@
this.name = LabelType.checkName(name);
}
- /** @return {@code SELF} or {@code ON_BEHALF_OF} (or labelAs). */
+ /** Returns {@code SELF} or {@code ON_BEHALF_OF} (or labelAs). */
public ForUser forUser() {
return forUser;
}
- /** @return name of the label, e.g. {@code "Code-Review"}. */
+ /** Returns name of the label, e.g. {@code "Code-Review"}. */
public String label() {
return name;
}
@@ -199,17 +199,17 @@
this.label = requireNonNull(label, "LabelVote");
}
- /** @return {@code SELF} or {@code ON_BEHALF_OF} (or labelAs). */
+ /** Returns {@code SELF} or {@code ON_BEHALF_OF} (or labelAs). */
public ForUser forUser() {
return forUser;
}
- /** @return name of the label, e.g. {@code "Code-Review"}. */
+ /** Returns name of the label, e.g. {@code "Code-Review"}. */
public String label() {
return label.label();
}
- /** @return specific value of the label, e.g. 1 or 2. */
+ /** Returns specific value of the label, e.g. 1 or 2. */
public short value() {
return label.value();
}
diff --git a/java/com/google/gerrit/server/permissions/PermissionCollection.java b/java/com/google/gerrit/server/permissions/PermissionCollection.java
index ddba52b..4b8db1c 100644
--- a/java/com/google/gerrit/server/permissions/PermissionCollection.java
+++ b/java/com/google/gerrit/server/permissions/PermissionCollection.java
@@ -277,8 +277,8 @@
}
/**
- * @return true if a "${username}" pattern might need to be expanded to build this collection,
- * making the results user specific.
+ * Returns true if a "${username}" pattern might need to be expanded to build this collection,
+ * making the results user specific.
*/
public boolean isUserSpecific() {
return perUser;
diff --git a/java/com/google/gerrit/server/permissions/ProjectControl.java b/java/com/google/gerrit/server/permissions/ProjectControl.java
index a92fde0..1203049 100644
--- a/java/com/google/gerrit/server/permissions/ProjectControl.java
+++ b/java/com/google/gerrit/server/permissions/ProjectControl.java
@@ -154,8 +154,8 @@
}
/**
- * @return {@code Capable.OK} if the user can upload to at least one reference. Does not check
- * Contributor Agreements.
+ * Returns {@code Capable.OK} if the user can upload to at least one reference. Does not check
+ * Contributor Agreements.
*/
boolean canPushToAtLeastOneRef() {
return canPerformOnAnyRef(Permission.PUSH)
diff --git a/java/com/google/gerrit/server/permissions/RefControl.java b/java/com/google/gerrit/server/permissions/RefControl.java
index f800207..6b51335 100644
--- a/java/com/google/gerrit/server/permissions/RefControl.java
+++ b/java/com/google/gerrit/server/permissions/RefControl.java
@@ -135,19 +135,19 @@
return hasReadPermissionOnRef;
}
- /** @return true if this user can add a new patch set to this ref */
+ /** Returns true if this user can add a new patch set to this ref */
boolean canAddPatchSet() {
return projectControl
.controlForRef(MagicBranch.NEW_CHANGE + refName)
.canPerform(Permission.ADD_PATCH_SET);
}
- /** @return true if this user can rebase changes on this ref */
+ /** Returns true if this user can rebase changes on this ref */
boolean canRebase() {
return canPerform(Permission.REBASE);
}
- /** @return true if this user can submit patch sets to this ref */
+ /** Returns true if this user can submit patch sets to this ref */
boolean canSubmit(boolean isChangeOwner) {
if (RefNames.REFS_CONFIG.equals(refName)) {
// Always allow project owners to submit configuration changes.
@@ -160,12 +160,12 @@
return canPerform(Permission.SUBMIT, isChangeOwner, false);
}
- /** @return true if this user can force edit topic names. */
+ /** Returns true if this user can force edit topic names. */
boolean canForceEditTopicName() {
return canPerform(Permission.EDIT_TOPIC_NAME, false, true);
}
- /** @return true if this user can delete changes. */
+ /** Returns true if this user can delete changes. */
boolean canDeleteChanges(boolean isChangeOwner) {
return canPerform(Permission.DELETE_CHANGES)
|| (isChangeOwner && canPerform(Permission.DELETE_OWN_CHANGES, isChangeOwner, false));
@@ -201,12 +201,12 @@
return canPerform(Permission.REVERT);
}
- /** @return true if this user can submit merge patch sets to this ref */
+ /** Returns true if this user can submit merge patch sets to this ref */
private boolean canUploadMerges() {
return projectControl.controlForRef("refs/for/" + refName).canPerform(Permission.PUSH_MERGE);
}
- /** @return true if the user can update the reference as a fast-forward. */
+ /** Returns true if the user can update the reference as a fast-forward. */
private boolean canUpdate() {
if (RefNames.REFS_CONFIG.equals(refName) && !projectControl.isOwner()) {
// Pushing requires being at least project owner, in addition to push.
@@ -225,7 +225,7 @@
return canPerform(Permission.PUSH);
}
- /** @return true if the user can rewind (force push) the reference. */
+ /** Returns true if the user can rewind (force push) the reference. */
private boolean canForceUpdate() {
if (canPushWithForce()) {
return true;
@@ -281,7 +281,7 @@
}
}
- /** @return true if this user can forge the author line in a commit. */
+ /** Returns true if this user can forge the author line in a commit. */
private boolean canForgeAuthor() {
if (canForgeAuthor == null) {
canForgeAuthor = canPerform(Permission.FORGE_AUTHOR);
@@ -289,7 +289,7 @@
return canForgeAuthor;
}
- /** @return true if this user can forge the committer line in a commit. */
+ /** Returns true if this user can forge the committer line in a commit. */
private boolean canForgeCommitter() {
if (canForgeCommitter == null) {
canForgeCommitter = canPerform(Permission.FORGE_COMMITTER);
@@ -297,7 +297,7 @@
return canForgeCommitter;
}
- /** @return true if this user can forge the server on the committer line. */
+ /** Returns true if this user can forge the server on the committer line. */
private boolean canForgeGerritServerIdentity() {
return canPerform(Permission.FORGE_SERVER);
}
@@ -364,7 +364,9 @@
}
return new PermissionRange(
- permissionName, Math.max(voteMin, blockAllowMin), Math.min(voteMax, blockAllowMax));
+ permissionName,
+ /* min= */ Math.max(voteMin, blockAllowMin),
+ /* max= */ Math.min(voteMax, blockAllowMax));
}
private boolean isBlocked(String permissionName, boolean isChangeOwner, boolean withForce) {
@@ -560,7 +562,8 @@
break;
case FORGE_COMMITTER:
pde.setAdvice(
- "You need 'Forge Committer' rights to push commits with another user as committer.");
+ "You need 'Forge Committer' rights to push commits with another user as"
+ + " committer.");
break;
case FORGE_SERVER:
pde.setAdvice(
diff --git a/java/com/google/gerrit/server/permissions/SectionSortCache.java b/java/com/google/gerrit/server/permissions/SectionSortCache.java
index d800782..e64f8b6 100644
--- a/java/com/google/gerrit/server/permissions/SectionSortCache.java
+++ b/java/com/google/gerrit/server/permissions/SectionSortCache.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
@@ -126,22 +127,22 @@
public abstract List<String> patterns();
- public abstract int cachedHashCode();
-
static EntryKey create(String refName, List<AccessSection> sections) {
- int hc = refName.hashCode();
List<String> patterns = new ArrayList<>(sections.size());
for (AccessSection s : sections) {
- String n = s.getName();
- patterns.add(n);
- hc = hc * 31 + n.hashCode();
+ patterns.add(s.getName());
}
- return new AutoValue_SectionSortCache_EntryKey(refName, ImmutableList.copyOf(patterns), hc);
+ return new AutoValue_SectionSortCache_EntryKey(refName, ImmutableList.copyOf(patterns));
}
+ @Memoized
@Override
- public final int hashCode() {
- return cachedHashCode();
+ public int hashCode() {
+ int hc = ref().hashCode();
+ for (String n : patterns()) {
+ hc = hc * 31 + n.hashCode();
+ }
+ return hc;
}
}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginContext.java b/java/com/google/gerrit/server/plugincontext/PluginContext.java
index 3c30745..a5fad56 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginContext.java
@@ -54,7 +54,7 @@
* <p>A plugin context can be manually opened by invoking the newTrace methods. This should only be
* needed if an extension throws multiple exceptions that need to be handled:
*
- * <pre>
+ * <pre>{@code
* public interface Foo {
* void doFoo() throws Exception1, Exception2, Exception3;
* }
@@ -66,7 +66,7 @@
* fooExtension.get().doFoo();
* }
* }
- * </pre>
+ * }</pre>
*
* <p>This class hosts static methods with generic functionality to invoke plugin extensions with a
* trace context that are commonly used by {@link PluginItemContext}, {@link PluginSetContext} and
@@ -121,11 +121,17 @@
@Inject
PluginMetrics(MetricMaker metricMaker) {
Field<String> pluginNameField =
- Field.ofString("plugin_name", Metadata.Builder::pluginName).build();
+ Field.ofString("plugin_name", Metadata.Builder::pluginName)
+ .description("The name of the plugin.")
+ .build();
Field<String> classNameField =
- Field.ofString("class_name", Metadata.Builder::className).build();
+ Field.ofString("class_name", Metadata.Builder::className)
+ .description("The class of the plugin that was invoked.")
+ .build();
Field<String> exportValueField =
- Field.ofString("export_value", Metadata.Builder::exportValue).build();
+ Field.ofString("export_value", Metadata.Builder::exportValue)
+ .description("The export name under which the invoked class is registered.")
+ .build();
this.latency =
metricMaker.newTimer(
diff --git a/java/com/google/gerrit/server/plugincontext/PluginItemContext.java b/java/com/google/gerrit/server/plugincontext/PluginItemContext.java
index 421b3ad..e88a6fe 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginItemContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginItemContext.java
@@ -40,46 +40,46 @@
*
* <p>Example if all exceptions should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* fooPluginItemContext.run(foo -> foo.doFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if all exceptions, but one, should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* try {
* fooPluginItemContext.run(foo -> foo.doFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result = fooPluginItemContext.call(foo -> foo.getFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if return values and a single exception should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result;
* try {
* result = fooPluginItemContext.call(foo -> foo.getFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if several exceptions should be handled:
*
- * <pre>
+ * <pre>{@code
* try (TraceContext traceContext = PluginContext.newTrace(fooDynamicItem.getEntry())) {
* fooDynamicItem.get().doFoo();
* } catch (MyException1 | MyException2 | MyException3 e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*/
public class PluginItemContext<T> {
@Nullable private final DynamicItem<T> dynamicItem;
diff --git a/java/com/google/gerrit/server/plugincontext/PluginMapContext.java b/java/com/google/gerrit/server/plugincontext/PluginMapContext.java
index b02ad27..fb50cd5 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginMapContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginMapContext.java
@@ -33,15 +33,15 @@
*
* <p>Example if all exceptions should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* fooPluginMapContext.runEach(
* extension -> results.put(extension.getExportName(), extension.get().getFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if all exceptions, but one, should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* try {
* fooPluginMapContext.runEach(
@@ -50,22 +50,22 @@
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values should be handled:
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* for (PluginMapEntryContext<Foo> c : fooPluginMapContext) {
* if (c.call(extension -> extension.get().handles(x))) {
* c.run(extension -> results.put(extension.getExportName(), extension.get().getFoo());
* }
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values and a single exception should be handled:
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* try {
* for (PluginMapEntryContext<Foo> c : fooPluginMapContext) {
@@ -77,11 +77,11 @@
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if several exceptions should be handled:
*
- * <pre>
+ * <pre>{@code
* for (Extension<Foo> fooExtension : fooDynamicMap) {
* try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
* fooExtension.get().doFoo();
@@ -89,7 +89,7 @@
* // handle the exception
* }
* }
- * </pre>
+ * }</pre>
*/
public class PluginMapContext<T> implements Iterable<PluginMapEntryContext<T>> {
private final DynamicMap<T> dynamicMap;
diff --git a/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java b/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java
index 68589cf..27181cb 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java
@@ -35,15 +35,15 @@
*
* <p>The call* methods execute the extension and deliver a result back to the caller.
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* fooPluginMapEntryContext.run(
* extension -> results.put(extension.getExportName(), extension.get().getFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if all exceptions, but one, should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* Map<String, Object> results = new HashMap<>();
* try {
* fooPluginMapEntryContext.run(
@@ -52,28 +52,28 @@
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if return values and a single exception should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result;
* try {
* result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if several exceptions should be handled:
*
- * <pre>
+ * <pre>{@code
* for (Extension<Foo> fooExtension : fooDynamicMap) {
* try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
* fooExtension.get().doFoo();
@@ -81,7 +81,7 @@
* // handle the exception
* }
* }
- * </pre>
+ * }</pre>
*/
public class PluginMapEntryContext<T> {
private final Extension<T> extension;
diff --git a/java/com/google/gerrit/server/plugincontext/PluginSetContext.java b/java/com/google/gerrit/server/plugincontext/PluginSetContext.java
index b64cfeb..43c9552 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginSetContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginSetContext.java
@@ -34,33 +34,33 @@
*
* <p>Example if all exceptions should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* fooPluginSetContext.runEach(foo -> foo.doFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if all exceptions, but one, should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* try {
* fooPluginSetContext.runEach(foo -> foo.doFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values should be handled:
*
- * <pre>
+ * <pre>{@code
* for (PluginSetEntryContext<Foo> c : fooPluginSetContext) {
* if (c.call(foo -> foo.handles(x))) {
* c.run(foo -> foo.doFoo());
* }
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values and a single exception should be handled:
*
- * <pre>
+ * <pre>{@code
* try {
* for (PluginSetEntryContext<Foo> c : fooPluginSetContext) {
* if (c.call(foo -> foo.handles(x), MyException.class)) {
@@ -70,11 +70,11 @@
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if several exceptions should be handled:
*
- * <pre>
+ * <pre>{@code
* for (Extension<Foo> fooExtension : fooDynamicSet.entries()) {
* try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
* fooExtension.get().doFoo();
@@ -82,7 +82,7 @@
* // handle the exception
* }
* }
- * </pre>
+ * }</pre>
*/
public class PluginSetContext<T> implements Iterable<PluginSetEntryContext<T>> {
private final DynamicSet<T> dynamicSet;
diff --git a/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
index 2268c07..be97b52 100644
--- a/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
+++ b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
@@ -37,40 +37,40 @@
*
* <p>Example if all exceptions should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* fooPluginSetEntryContext.run(foo -> foo.doFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if all exceptions, but one, should be caught and logged:
*
- * <pre>
+ * <pre>{@code
* try {
* fooPluginSetEntryContext.run(foo -> foo.doFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if return values should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result = fooPluginSetEntryContext.call(foo -> foo.getFoo());
- * </pre>
+ * }</pre>
*
* <p>Example if return values and a single exception should be handled:
*
- * <pre>
+ * <pre>{@code
* Object result;
* try {
* result = fooPluginSetEntryContext.call(foo -> foo.getFoo(), MyException.class);
* } catch (MyException e) {
* // handle the exception
* }
- * </pre>
+ * }</pre>
*
* <p>Example if several exceptions should be handled:
*
- * <pre>
+ * <pre>{@code
* for (Extension<Foo> fooExtension : fooDynamicSet.entries()) {
* try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
* fooExtension.get().doFoo();
@@ -78,7 +78,7 @@
* // handle the exception
* }
* }
- * </pre>
+ * }</pre>
*/
public class PluginSetEntryContext<T> {
private final Extension<T> extension;
diff --git a/java/com/google/gerrit/server/project/ProjectCache.java b/java/com/google/gerrit/server/project/ProjectCache.java
index cd41ce5..fee7105 100644
--- a/java/com/google/gerrit/server/project/ProjectCache.java
+++ b/java/com/google/gerrit/server/project/ProjectCache.java
@@ -42,10 +42,10 @@
return () -> new NoSuchProjectException(nameKey);
}
- /** @return the parent state for all projects on this server. */
+ /** Returns the parent state for all projects on this server. */
ProjectState getAllProjects();
- /** @return the project state of the project storing meta data for all users. */
+ /** Returns the project state of the project storing meta data for all users. */
ProjectState getAllUsers();
/**
@@ -84,12 +84,12 @@
*/
void remove(Project.NameKey name);
- /** @return sorted iteration of projects. */
+ /** Returns sorted iteration of projects. */
ImmutableSortedSet<Project.NameKey> all();
/**
- * @return estimated set of relevant groups extracted from hot project access rules. If the cache
- * is cold or too small for the entire project set of the server, this set may be incomplete.
+ * Returns estimated set of relevant groups extracted from hot project access rules. If the cache
+ * is cold or too small for the entire project set of the server, this set may be incomplete.
*/
Set<AccountGroup.UUID> guessRelevantGroupUUIDs();
diff --git a/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index e69967c..de27afa 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -51,9 +51,9 @@
import com.google.gerrit.server.cache.serialize.ObjectIdConverter;
import com.google.gerrit.server.cache.serialize.ProtobufSerializer;
import com.google.gerrit.server.cache.serialize.entities.CachedProjectConfigSerializer;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.logging.Metadata;
import com.google.gerrit.server.logging.TraceContext;
@@ -78,8 +78,7 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.storage.file.FileBasedConfig;
-import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.lib.StoredConfig;
/**
* Cache of project information, including access rights.
@@ -304,27 +303,22 @@
/**
* Returns a {@code MurMur128} hash of the contents of {@code etc/All-Projects-project.config}.
*/
- public static byte[] allProjectsFileProjectConfigHash(
- AllProjectsName allProjectsName, SitePaths sitePaths) {
+ public static byte[] allProjectsFileProjectConfigHash(Optional<StoredConfig> allProjectsConfig) {
// Hash the contents of All-Projects-project.config
// This is a way for administrators to orchestrate project.config changes across many Gerrit
// instances.
// When this file changes, we need to make sure we disregard persistently cached project
// state.
- FileBasedConfig fileBasedConfig =
- new FileBasedConfig(
- sitePaths
- .etc_dir
- .resolve(allProjectsName.get())
- .resolve(ProjectConfig.PROJECT_CONFIG)
- .toFile(),
- FS.DETECTED);
+ if (!allProjectsConfig.isPresent()) {
+ // If the project.config file is not present, this is equal to an empty config file:
+ return Hashing.murmur3_128().hashString("", UTF_8).asBytes();
+ }
try {
- fileBasedConfig.load();
+ allProjectsConfig.get().load();
} catch (IOException | ConfigInvalidException e) {
throw new IllegalStateException(e);
}
- return Hashing.murmur3_128().hashString(fileBasedConfig.toText(), UTF_8).asBytes();
+ return Hashing.murmur3_128().hashString(allProjectsConfig.get().toText(), UTF_8).asBytes();
}
@Singleton
@@ -334,7 +328,7 @@
private final ListeningExecutorService cacheRefreshExecutor;
private final Counter2<String, Boolean> refreshCounter;
private final AllProjectsName allProjectsName;
- private final SitePaths sitePaths;
+ private final AllProjectsConfigProvider allProjectsConfigProvider;
@Inject
InMemoryLoader(
@@ -344,18 +338,25 @@
@CacheRefreshExecutor ListeningExecutorService cacheRefreshExecutor,
MetricMaker metricMaker,
AllProjectsName allProjectsName,
- SitePaths sitePaths) {
+ AllProjectsConfigProvider allProjectsConfigProvider) {
this.persistedCache = persistedCache;
this.repoManager = repoManager;
this.cacheRefreshExecutor = cacheRefreshExecutor;
refreshCounter =
metricMaker.newCounter(
"caches/refresh_count",
- new Description("count").setRate(),
- Field.ofString("cache", Metadata.Builder::className).build(),
- Field.ofBoolean("outdated", Metadata.Builder::outdated).build());
+ new Description(
+ "The number of refreshes per cache with an indicator if a reload was"
+ + " necessary.")
+ .setRate(),
+ Field.ofString("cache", Metadata.Builder::className)
+ .description("The name of the cache.")
+ .build(),
+ Field.ofBoolean("outdated", Metadata.Builder::outdated)
+ .description("Whether the cache entry was outdated on reload.")
+ .build());
this.allProjectsName = allProjectsName;
- this.sitePaths = sitePaths;
+ this.allProjectsConfigProvider = allProjectsConfigProvider;
}
@Override
@@ -369,7 +370,8 @@
Cache.ProjectCacheKeyProto.newBuilder().setProject(key.get());
Ref configRef = git.exactRef(RefNames.REFS_CONFIG);
if (key.get().equals(allProjectsName.get())) {
- byte[] fileHash = allProjectsFileProjectConfigHash(allProjectsName, sitePaths);
+ Optional<StoredConfig> allProjectsConfig = allProjectsConfigProvider.get(allProjectsName);
+ byte[] fileHash = allProjectsFileProjectConfigHash(allProjectsConfig);
keyProto.setGlobalConfigRevision(ByteString.copyFrom(fileHash));
}
if (configRef != null) {
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index 0d710b9..513aeed 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -64,10 +64,10 @@
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.PluginConfig;
-import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.ValidationError;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
@@ -98,8 +98,6 @@
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevWalk;
-import org.eclipse.jgit.storage.file.FileBasedConfig;
-import org.eclipse.jgit.util.FS;
public class ProjectConfig extends VersionedMetaData implements ValidationError.Sink {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -203,28 +201,21 @@
// ProjectCache, so this would retain lots more memory.
@Singleton
public static class Factory {
- @Nullable
- public static StoredConfig getBaseConfig(
- SitePaths sitePaths, AllProjectsName allProjects, Project.NameKey projectName) {
- return projectName.equals(allProjects)
- // Delay loading till onLoad method.
- ? new FileBasedConfig(
- sitePaths.etc_dir.resolve(allProjects.get()).resolve(PROJECT_CONFIG).toFile(),
- FS.DETECTED)
- : null;
- }
-
- private final SitePaths sitePaths;
- private final AllProjectsName allProjects;
+ private final AllProjectsName allProjectsName;
+ private final AllProjectsConfigProvider allProjectsConfigProvider;
@Inject
- Factory(SitePaths sitePaths, AllProjectsName allProjects) {
- this.sitePaths = sitePaths;
- this.allProjects = allProjects;
+ Factory(AllProjectsName allProjectsName, AllProjectsConfigProvider allProjectsConfigProvider) {
+ this.allProjectsName = allProjectsName;
+ this.allProjectsConfigProvider = allProjectsConfigProvider;
}
public ProjectConfig create(Project.NameKey projectName) {
- return new ProjectConfig(projectName, getBaseConfig(sitePaths, allProjects, projectName));
+ return new ProjectConfig(
+ projectName,
+ projectName.equals(allProjectsName)
+ ? allProjectsConfigProvider.get(allProjectsName)
+ : Optional.empty());
}
public ProjectConfig read(MetaDataUpdate update) throws IOException, ConfigInvalidException {
@@ -249,7 +240,7 @@
}
}
- private final StoredConfig baseConfig;
+ private final Optional<StoredConfig> baseConfig;
private Project project;
private AccountsSection accountsSection;
@@ -355,7 +346,7 @@
requireNonNull(commentLinkSections.remove(name));
}
- private ProjectConfig(Project.NameKey projectName, @Nullable StoredConfig baseConfig) {
+ private ProjectConfig(Project.NameKey projectName, Optional<StoredConfig> baseConfig) {
this.projectName = projectName;
this.baseConfig = baseConfig;
}
@@ -569,32 +560,32 @@
groupList.renameGroup(uuid, newName);
}
- /** @return the group reference, if the group is used by at least one rule. */
+ /** Returns the group reference, if the group is used by at least one rule. */
public GroupReference getGroup(AccountGroup.UUID uuid) {
return groupList.byUUID(uuid);
}
/**
- * @return the group reference corresponding to the specified group name if the group is used by
- * at least one rule or plugin value.
+ * Returns the group reference corresponding to the specified group name if the group is used by
+ * at least one rule or plugin value.
*/
public GroupReference getGroup(String groupName) {
return groupList.byName(groupName);
}
/**
- * @return the project's rules.pl ObjectId, if present in the branch. Null if it doesn't exist.
+ * Returns the project's rules.pl ObjectId, if present in the branch. Null if it doesn't exist.
*/
public ObjectId getRulesId() {
return rulesId;
}
- /** @return the maxObjectSizeLimit configured on this project, or zero if not configured. */
+ /** Returns the maxObjectSizeLimit configured on this project, or zero if not configured. */
public long getMaxObjectSizeLimit() {
return maxObjectSizeLimit;
}
- /** @return the checkReceivedObjects for this project, default is true. */
+ /** Returns the checkReceivedObjects for this project, default is true. */
public boolean getCheckReceivedObjects() {
return checkReceivedObjects;
}
@@ -636,8 +627,8 @@
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
- if (baseConfig != null) {
- baseConfig.load();
+ if (baseConfig.isPresent()) {
+ baseConfig.get().load();
}
readGroupList();
diff --git a/java/com/google/gerrit/server/project/ProjectCreator.java b/java/com/google/gerrit/server/project/ProjectCreator.java
index c382f04..4e778a4 100644
--- a/java/com/google/gerrit/server/project/ProjectCreator.java
+++ b/java/com/google/gerrit/server/project/ProjectCreator.java
@@ -39,7 +39,8 @@
import com.google.gerrit.server.extensions.events.AbstractNoNotifyEvent;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.git.RepositoryCaseMismatchException;
+import com.google.gerrit.server.git.GitRepositoryManager.Status;
+import com.google.gerrit.server.git.RepositoryExistsException;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
@@ -107,12 +108,9 @@
final Project.NameKey nameKey = args.getProject();
try {
final String head = args.permissionsOnly ? RefNames.REFS_CONFIG : args.branch.get(0);
- try (Repository repo = repoManager.openRepository(nameKey)) {
- if (repo.getObjectDatabase().exists()) {
- throw new ResourceConflictException("project \"" + nameKey + "\" exists");
- }
- } catch (RepositoryNotFoundException e) {
- // It does not exist, safe to ignore.
+ Status status = repoManager.getRepositoryStatus(nameKey);
+ if (!status.equals(Status.NON_EXISTENT)) {
+ throw new RepositoryExistsException(nameKey, "Repository status: " + status);
}
try (Repository repo = repoManager.createRepository(nameKey)) {
RefUpdate u = repo.updateRef(Constants.HEAD);
@@ -129,13 +127,11 @@
return projectCache.get(nameKey).orElseThrow(illegalState(nameKey));
}
- } catch (RepositoryCaseMismatchException e) {
+ } catch (RepositoryExistsException e) {
throw new ResourceConflictException(
"Cannot create "
+ nameKey.get()
- + " because the name is already occupied by another project."
- + " The other project has the same name, only spelled in a"
- + " different case.",
+ + " because the name is already occupied by another project.",
e);
} catch (RepositoryNotFoundException badName) {
throw new BadRequestException("invalid project name: " + nameKey, badName);
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index 4569027..69e6036 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -138,8 +138,8 @@
}
/**
- * @return cached computation of all global capabilities. This should only be invoked on the state
- * from {@link ProjectCache#getAllProjects()}. Null on any other project.
+ * Returns cached computation of all global capabilities. This should only be invoked on the state
+ * from {@link ProjectCache#getAllProjects()}. Null on any other project.
*/
public CapabilityCollection getCapabilityCollection() {
return capabilities;
@@ -316,9 +316,9 @@
}
/**
- * @return all {@link AccountGroup}'s to which the owner privilege for 'refs/*' is assigned for
- * this project (the local owners), if there are no local owners the local owners of the
- * nearest parent project that has local owners are returned
+ * Returns all {@link AccountGroup}'s to which the owner privilege for 'refs/*' is assigned for
+ * this project (the local owners), if there are no local owners the local owners of the nearest
+ * parent project that has local owners are returned
*/
public Set<AccountGroup.UUID> getOwners() {
for (ProjectState p : tree()) {
@@ -330,10 +330,10 @@
}
/**
- * @return all {@link AccountGroup}'s that are allowed to administrate the complete project. This
- * includes all groups to which the owner privilege for 'refs/*' is assigned for this project
- * (the local owners) and all groups to which the owner privilege for 'refs/*' is assigned for
- * one of the parent projects (the inherited owners).
+ * Returns all {@link AccountGroup}'s that are allowed to administrate the complete project. This
+ * includes all groups to which the owner privilege for 'refs/*' is assigned for this project (the
+ * local owners) and all groups to which the owner privilege for 'refs/*' is assigned for one of
+ * the parent projects (the inherited owners).
*/
public Set<AccountGroup.UUID> getAllOwners() {
Set<AccountGroup.UUID> result = new HashSet<>();
@@ -346,16 +346,16 @@
}
/**
- * @return an iterable that walks through this project and then the parents of this project.
- * Starts from this project and progresses up the hierarchy to All-Projects.
+ * Returns an iterable that walks through this project and then the parents of this project.
+ * Starts from this project and progresses up the hierarchy to All-Projects.
*/
public Iterable<ProjectState> tree() {
return () -> new ProjectHierarchyIterator(projectCache, allProjectsName, ProjectState.this);
}
/**
- * @return an iterable that walks in-order from All-Projects through the project hierarchy to this
- * project.
+ * Returns an iterable that walks in-order from All-Projects through the project hierarchy to this
+ * project.
*/
public Iterable<ProjectState> treeInOrder() {
List<ProjectState> projects = Lists.newArrayList(tree());
@@ -364,8 +364,8 @@
}
/**
- * @return an iterable that walks through the parents of this project. Starts from the immediate
- * parent of this project and progresses up the hierarchy to All-Projects.
+ * Returns an iterable that walks through the parents of this project. Starts from the immediate
+ * parent of this project and progresses up the hierarchy to All-Projects.
*/
public FluentIterable<ProjectState> parents() {
return FluentIterable.from(tree()).skip(1);
diff --git a/java/com/google/gerrit/server/project/Reachable.java b/java/com/google/gerrit/server/project/Reachable.java
index 2adebe7..342c2bc 100644
--- a/java/com/google/gerrit/server/project/Reachable.java
+++ b/java/com/google/gerrit/server/project/Reachable.java
@@ -55,9 +55,9 @@
}
/**
- * @return true if a commit is reachable from a given set of refs. This method enforces
- * permissions on the given set of refs and performs a reachability check. Tags are not
- * filtered separately and will only be returned if reachable by a provided ref.
+ * Returns true if a commit is reachable from a given set of refs. This method enforces
+ * permissions on the given set of refs and performs a reachability check. Tags are not filtered
+ * separately and will only be returned if reachable by a provided ref.
*/
public boolean fromRefs(
Project.NameKey project, Repository repo, RevCommit commit, List<Ref> refs) {
diff --git a/java/com/google/gerrit/server/project/RefResource.java b/java/com/google/gerrit/server/project/RefResource.java
index ac2735d..fcf6048 100644
--- a/java/com/google/gerrit/server/project/RefResource.java
+++ b/java/com/google/gerrit/server/project/RefResource.java
@@ -22,9 +22,9 @@
super(projectState, user);
}
- /** @return the ref's name */
+ /** Returns the ref's name */
public abstract String getRef();
- /** @return the ref's revision */
+ /** Returns the ref's revision */
public abstract String getRevision();
}
diff --git a/java/com/google/gerrit/server/project/RemoveReviewerControl.java b/java/com/google/gerrit/server/project/RemoveReviewerControl.java
index 652c49f..0336e8e 100644
--- a/java/com/google/gerrit/server/project/RemoveReviewerControl.java
+++ b/java/com/google/gerrit/server/project/RemoveReviewerControl.java
@@ -62,7 +62,7 @@
checkRemoveReviewer(notes, currentUser, reviewer, 0);
}
- /** @return true if the user is allowed to remove this reviewer. */
+ /** Returns true if the user is allowed to remove this reviewer. */
public boolean testRemoveReviewer(
ChangeData cd, CurrentUser currentUser, Account.Id reviewer, int value)
throws PermissionBackendException {
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
new file mode 100644
index 0000000..f028def
--- /dev/null
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsAdapter.java
@@ -0,0 +1,198 @@
+// 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.project;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.MoreCollectors;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.entities.SubmitRecord.Label;
+import com.google.gerrit.entities.SubmitRequirement;
+import com.google.gerrit.entities.SubmitRequirementExpression;
+import com.google.gerrit.entities.SubmitRequirementExpressionResult;
+import com.google.gerrit.entities.SubmitRequirementExpressionResult.Status;
+import com.google.gerrit.entities.SubmitRequirementResult;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import java.util.List;
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * Convert {@link com.google.gerrit.entities.SubmitRecord} entities to {@link
+ * com.google.gerrit.entities.SubmitRequirementResult}s.
+ */
+public class SubmitRequirementsAdapter {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ private SubmitRequirementsAdapter() {}
+
+ public static List<SubmitRequirementResult> createResult(
+ SubmitRecord record, List<LabelType> labelTypes, ObjectId psCommitId) {
+ List<SubmitRequirementResult> results;
+ if (record.ruleName.equals("gerrit~DefaultSubmitRule")) {
+ results = createFromDefaultSubmitRecord(record.labels, labelTypes, psCommitId);
+ } else {
+ results = createFromCustomSubmitRecord(record, psCommitId);
+ }
+ logger.atFine().log("Converted submit record %s to submit requirements %s", record, results);
+ return results;
+ }
+
+ private static List<SubmitRequirementResult> createFromDefaultSubmitRecord(
+ List<Label> labels, List<LabelType> labelTypes, ObjectId psCommitId) {
+ ImmutableList.Builder<SubmitRequirementResult> result = ImmutableList.builder();
+ for (Label label : labels) {
+ LabelType labelType = getLabelType(labelTypes, label.label);
+ if (!isBlocking(labelType)) {
+ continue;
+ }
+ ImmutableList<String> atoms = toExpressionAtomList(labelType);
+ SubmitRequirement.Builder req =
+ SubmitRequirement.builder()
+ .setName(label.label)
+ .setSubmittabilityExpression(toExpression(atoms))
+ .setAllowOverrideInChildProjects(labelType.isCanOverride());
+ result.add(
+ SubmitRequirementResult.builder()
+ .legacy(true)
+ .submitRequirement(req.build())
+ .submittabilityExpressionResult(
+ createExpressionResult(toExpression(atoms), mapStatus(label), atoms))
+ .patchSetCommitId(psCommitId)
+ .build());
+ }
+ return result.build();
+ }
+
+ private static List<SubmitRequirementResult> createFromCustomSubmitRecord(
+ SubmitRecord record, ObjectId psCommitId) {
+ if (record.labels == null || record.labels.isEmpty()) {
+ SubmitRequirement sr =
+ SubmitRequirement.builder()
+ .setName(record.ruleName)
+ .setSubmittabilityExpression(
+ SubmitRequirementExpression.create(String.format("rule:%s", record.ruleName)))
+ .setAllowOverrideInChildProjects(false)
+ .build();
+ return ImmutableList.of(
+ SubmitRequirementResult.builder()
+ .legacy(true)
+ .submitRequirement(sr)
+ .submittabilityExpressionResult(
+ createExpressionResult(
+ sr.submittabilityExpression(),
+ mapStatus(record),
+ ImmutableList.of(record.ruleName)))
+ .patchSetCommitId(psCommitId)
+ .build());
+ }
+ ImmutableList.Builder<SubmitRequirementResult> result = ImmutableList.builder();
+ for (Label label : record.labels) {
+ String expressionString = String.format("label:%s=%s", label.label, record.ruleName);
+ SubmitRequirement sr =
+ SubmitRequirement.builder()
+ .setName(label.label)
+ .setSubmittabilityExpression(SubmitRequirementExpression.create(expressionString))
+ .setAllowOverrideInChildProjects(false)
+ .build();
+ result.add(
+ SubmitRequirementResult.builder()
+ .legacy(true)
+ .submitRequirement(sr)
+ .submittabilityExpressionResult(
+ createExpressionResult(
+ sr.submittabilityExpression(),
+ mapStatus(label),
+ ImmutableList.of(expressionString)))
+ .patchSetCommitId(psCommitId)
+ .build());
+ }
+ return result.build();
+ }
+
+ private static boolean isBlocking(LabelType labelType) {
+ return labelType.getFunction().isBlock() || labelType.getFunction().isRequired();
+ }
+
+ private static SubmitRequirementExpression toExpression(List<String> atoms) {
+ return SubmitRequirementExpression.create(String.join(" ", atoms));
+ }
+
+ private static ImmutableList<String> toExpressionAtomList(LabelType lt) {
+ String ignoreSelfApproval =
+ lt.isIgnoreSelfApproval() ? ",user=" + ChangeQueryBuilder.ARG_ID_NON_UPLOADER : "";
+ switch (lt.getFunction()) {
+ case MAX_WITH_BLOCK:
+ return ImmutableList.of(
+ String.format("label:%s=MAX", lt.getName()) + ignoreSelfApproval,
+ String.format("-label:%s=MIN", lt.getName()));
+ case ANY_WITH_BLOCK:
+ return ImmutableList.of(String.format(String.format("-label:%s=MIN", lt.getName())));
+ case MAX_NO_BLOCK:
+ return ImmutableList.of(
+ String.format(String.format("label:%s=MAX", lt.getName())) + ignoreSelfApproval);
+ case NO_BLOCK:
+ case NO_OP:
+ case PATCH_SET_LOCK:
+ default:
+ return ImmutableList.of();
+ }
+ }
+
+ private static Status mapStatus(Label label) {
+ SubmitRequirementExpressionResult.Status status = Status.PASS;
+ switch (label.status) {
+ case OK:
+ case MAY:
+ status = Status.PASS;
+ break;
+ case REJECT:
+ case NEED:
+ case IMPOSSIBLE:
+ status = Status.FAIL;
+ break;
+ }
+ return status;
+ }
+
+ private static Status mapStatus(SubmitRecord submitRecord) {
+ switch (submitRecord.status) {
+ case OK:
+ case CLOSED:
+ case FORCED:
+ return Status.PASS;
+ case NOT_READY:
+ return Status.FAIL;
+ case RULE_ERROR:
+ default:
+ return Status.ERROR;
+ }
+ }
+
+ private static SubmitRequirementExpressionResult createExpressionResult(
+ SubmitRequirementExpression expression, Status status, ImmutableList<String> atoms) {
+ return SubmitRequirementExpressionResult.create(
+ expression,
+ status,
+ status == Status.PASS ? atoms : ImmutableList.of(),
+ status == Status.FAIL ? atoms : ImmutableList.of());
+ }
+
+ private static LabelType getLabelType(List<LabelType> labelTypes, String labelName) {
+ return labelTypes.stream()
+ .filter(lt -> lt.getName().equals(labelName))
+ .collect(MoreCollectors.onlyElement());
+ }
+}
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsEvaluator.java b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluator.java
index fad90df..b3ac380 100644
--- a/java/com/google/gerrit/server/project/SubmitRequirementsEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluator.java
@@ -14,36 +14,27 @@
package com.google.gerrit.server.project;
-import static com.google.gerrit.server.project.ProjectCache.illegalState;
-
-import com.google.common.collect.ImmutableMap;
import com.google.gerrit.entities.SubmitRequirement;
import com.google.gerrit.entities.SubmitRequirementExpression;
import com.google.gerrit.entities.SubmitRequirementExpressionResult;
-import com.google.gerrit.entities.SubmitRequirementExpressionResult.PredicateResult;
import com.google.gerrit.entities.SubmitRequirementResult;
-import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.query.change.ChangeQueryBuilder;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
import java.util.Map;
-import java.util.Optional;
-/** Evaluates submit requirements for different change data. */
-@Singleton
-public class SubmitRequirementsEvaluator {
- private final Provider<ChangeQueryBuilder> changeQueryBuilderProvider;
- private final ProjectCache projectCache;
+public interface SubmitRequirementsEvaluator {
+ /**
+ * Evaluate and return all submit requirement results for a change. Submit requirements are read
+ * from the project config of the project containing the change as well as parent projects.
+ */
+ Map<SubmitRequirement, SubmitRequirementResult> evaluateAllRequirements(ChangeData cd);
- @Inject
- private SubmitRequirementsEvaluator(
- Provider<ChangeQueryBuilder> changeQueryBuilderProvider, ProjectCache projectCache) {
- this.changeQueryBuilderProvider = changeQueryBuilderProvider;
- this.projectCache = projectCache;
- }
+ /** Evaluate a single {@link SubmitRequirement} using change data. */
+ SubmitRequirementResult evaluateRequirement(SubmitRequirement sr, ChangeData cd);
+
+ /** Evaluate a {@link SubmitRequirementExpression} using change data. */
+ SubmitRequirementExpressionResult evaluateExpression(
+ SubmitRequirementExpression expression, ChangeData changeData);
/**
* Validate a {@link SubmitRequirementExpression}. Callers who wish to validate submit
@@ -52,74 +43,5 @@
* @param expression entity containing the expression string.
* @throws QueryParseException the expression string contains invalid syntax and can't be parsed.
*/
- public void validateExpression(SubmitRequirementExpression expression)
- throws QueryParseException {
- changeQueryBuilderProvider.get().parse(expression.expressionString());
- }
-
- /**
- * Evaluate and return all submit requirements for a change. Submit requirements are retrieved for
- * the project containing the change and parent projects as well.
- */
- public Map<SubmitRequirement, SubmitRequirementResult> getResults(ChangeData cd) {
- ProjectState state = projectCache.get(cd.project()).orElseThrow(illegalState(cd.project()));
- Map<String, SubmitRequirement> requirements = state.getSubmitRequirements();
- ImmutableMap.Builder<SubmitRequirement, SubmitRequirementResult> result =
- ImmutableMap.builderWithExpectedSize(requirements.size());
- for (SubmitRequirement requirement : requirements.values()) {
- result.put(requirement, evaluate(requirement, cd));
- }
- return result.build();
- }
-
- /** Evaluate a {@link SubmitRequirement} on a given {@link ChangeData}. */
- public SubmitRequirementResult evaluate(SubmitRequirement sr, ChangeData cd) {
- SubmitRequirementExpressionResult blockingResult =
- evaluateExpression(sr.submittabilityExpression(), cd);
-
- Optional<SubmitRequirementExpressionResult> applicabilityResult =
- sr.applicabilityExpression().isPresent()
- ? Optional.of(evaluateExpression(sr.applicabilityExpression().get(), cd))
- : Optional.empty();
-
- Optional<SubmitRequirementExpressionResult> overrideResult =
- sr.overrideExpression().isPresent()
- ? Optional.of(evaluateExpression(sr.overrideExpression().get(), cd))
- : Optional.empty();
-
- return SubmitRequirementResult.builder()
- .submitRequirement(sr)
- .patchSetCommitId(cd.currentPatchSet().commitId())
- .submittabilityExpressionResult(blockingResult)
- .applicabilityExpressionResult(applicabilityResult)
- .overrideExpressionResult(overrideResult)
- .build();
- }
-
- /** Evaluate a {@link SubmitRequirementExpression} using change data. */
- public SubmitRequirementExpressionResult evaluateExpression(
- SubmitRequirementExpression expression, ChangeData changeData) {
- try {
- Predicate<ChangeData> predicate =
- changeQueryBuilderProvider.get().parse(expression.expressionString());
- PredicateResult predicateResult = evaluatePredicateTree(predicate, changeData);
- return SubmitRequirementExpressionResult.create(expression, predicateResult);
- } catch (QueryParseException e) {
- return SubmitRequirementExpressionResult.error(expression, e.getMessage());
- }
- }
-
- /** Evaluate the predicate recursively using change data. */
- private PredicateResult evaluatePredicateTree(
- Predicate<ChangeData> predicate, ChangeData changeData) {
- PredicateResult.Builder predicateResult =
- PredicateResult.builder()
- .predicateString(predicate.isLeaf() ? predicate.getPredicateString() : "")
- .status(predicate.asMatchable().match(changeData));
- predicate
- .getChildren()
- .forEach(
- c -> predicateResult.addChildPredicateResult(evaluatePredicateTree(c, changeData)));
- return predicateResult.build();
- }
+ void validateExpression(SubmitRequirementExpression expression) throws QueryParseException;
}
diff --git a/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java
new file mode 100644
index 0000000..9be50c7
--- /dev/null
+++ b/java/com/google/gerrit/server/project/SubmitRequirementsEvaluatorImpl.java
@@ -0,0 +1,173 @@
+// 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.project;
+
+import static com.google.gerrit.server.project.ProjectCache.illegalState;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.entities.SubmitRequirement;
+import com.google.gerrit.entities.SubmitRequirementExpression;
+import com.google.gerrit.entities.SubmitRequirementExpressionResult;
+import com.google.gerrit.entities.SubmitRequirementExpressionResult.PredicateResult;
+import com.google.gerrit.entities.SubmitRequirementResult;
+import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.server.experiments.ExperimentFeatures;
+import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.Scopes;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.eclipse.jgit.lib.ObjectId;
+
+/** Evaluates submit requirements for different change data. */
+public class SubmitRequirementsEvaluatorImpl implements SubmitRequirementsEvaluator {
+
+ private final Provider<ChangeQueryBuilder> changeQueryBuilderProvider;
+ private final ProjectCache projectCache;
+ private final SubmitRuleEvaluator.Factory legacyEvaluator;
+ private final ExperimentFeatures experimentFeatures;
+
+ public static Module module() {
+ return new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(SubmitRequirementsEvaluator.class)
+ .to(SubmitRequirementsEvaluatorImpl.class)
+ .in(Scopes.SINGLETON);
+ }
+ };
+ }
+
+ @Inject
+ private SubmitRequirementsEvaluatorImpl(
+ Provider<ChangeQueryBuilder> changeQueryBuilderProvider,
+ ProjectCache projectCache,
+ SubmitRuleEvaluator.Factory legacyEvaluator,
+ ExperimentFeatures experimentFeatures) {
+ this.changeQueryBuilderProvider = changeQueryBuilderProvider;
+ this.projectCache = projectCache;
+ this.legacyEvaluator = legacyEvaluator;
+ this.experimentFeatures = experimentFeatures;
+ }
+
+ @Override
+ public void validateExpression(SubmitRequirementExpression expression)
+ throws QueryParseException {
+ changeQueryBuilderProvider.get().parse(expression.expressionString());
+ }
+
+ @Override
+ public Map<SubmitRequirement, SubmitRequirementResult> evaluateAllRequirements(ChangeData cd) {
+ Map<SubmitRequirement, SubmitRequirementResult> result = getRequirements(cd);
+ if (experimentFeatures.isFeatureEnabled(
+ ExperimentFeaturesConstants
+ .GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_LEGACY_SUBMIT_REQUIREMENTS)) {
+ result.putAll(getLegacyRequirements(cd));
+ }
+ return ImmutableMap.copyOf(result);
+ }
+
+ @Override
+ public SubmitRequirementResult evaluateRequirement(SubmitRequirement sr, ChangeData cd) {
+ SubmitRequirementExpressionResult blockingResult =
+ evaluateExpression(sr.submittabilityExpression(), cd);
+
+ Optional<SubmitRequirementExpressionResult> applicabilityResult =
+ sr.applicabilityExpression().isPresent()
+ ? Optional.of(evaluateExpression(sr.applicabilityExpression().get(), cd))
+ : Optional.empty();
+
+ Optional<SubmitRequirementExpressionResult> overrideResult =
+ sr.overrideExpression().isPresent()
+ ? Optional.of(evaluateExpression(sr.overrideExpression().get(), cd))
+ : Optional.empty();
+
+ return SubmitRequirementResult.builder()
+ .legacy(false)
+ .submitRequirement(sr)
+ .patchSetCommitId(cd.currentPatchSet().commitId())
+ .submittabilityExpressionResult(blockingResult)
+ .applicabilityExpressionResult(applicabilityResult)
+ .overrideExpressionResult(overrideResult)
+ .build();
+ }
+
+ @Override
+ public SubmitRequirementExpressionResult evaluateExpression(
+ SubmitRequirementExpression expression, ChangeData changeData) {
+ try {
+ Predicate<ChangeData> predicate =
+ changeQueryBuilderProvider.get().parse(expression.expressionString());
+ PredicateResult predicateResult = evaluatePredicateTree(predicate, changeData);
+ return SubmitRequirementExpressionResult.create(expression, predicateResult);
+ } catch (QueryParseException e) {
+ return SubmitRequirementExpressionResult.error(expression, e.getMessage());
+ }
+ }
+
+ /** Evaluate and return submit requirements stored in this project's config and its parents. */
+ private Map<SubmitRequirement, SubmitRequirementResult> getRequirements(ChangeData cd) {
+ ProjectState state = projectCache.get(cd.project()).orElseThrow(illegalState(cd.project()));
+ Map<String, SubmitRequirement> requirements = state.getSubmitRequirements();
+ Map<SubmitRequirement, SubmitRequirementResult> result = new HashMap<>();
+ for (SubmitRequirement requirement : requirements.values()) {
+ result.put(requirement, evaluateRequirement(requirement, cd));
+ }
+ return result;
+ }
+
+ /**
+ * Convert and return legacy submit records (created by label functions and other {@link
+ * com.google.gerrit.server.rules.SubmitRule}s to submit requirement results.
+ */
+ private Map<SubmitRequirement, SubmitRequirementResult> getLegacyRequirements(ChangeData cd) {
+ // We use SubmitRuleOptions.defaults() which does not recompute submit rules for closed changes.
+ // This doesn't have an effect since we never call this class (i.e. to evaluate submit
+ // requirements) for closed changes.
+ List<SubmitRecord> records = legacyEvaluator.create(SubmitRuleOptions.defaults()).evaluate(cd);
+ List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
+ ObjectId commitId = cd.currentPatchSet().commitId();
+ return records.stream()
+ .map(r -> SubmitRequirementsAdapter.createResult(r, labelTypes, commitId))
+ .flatMap(List::stream)
+ .collect(Collectors.toMap(sr -> sr.submitRequirement(), Function.identity()));
+ }
+
+ /** Evaluate the predicate recursively using change data. */
+ private PredicateResult evaluatePredicateTree(
+ Predicate<ChangeData> predicate, ChangeData changeData) {
+ PredicateResult.Builder predicateResult =
+ PredicateResult.builder()
+ .predicateString(predicate.isLeaf() ? predicate.getPredicateString() : "")
+ .status(predicate.asMatchable().match(changeData));
+ predicate
+ .getChildren()
+ .forEach(
+ c -> predicateResult.addChildPredicateResult(evaluatePredicateTree(c, changeData)));
+ return predicateResult.build();
+ }
+}
diff --git a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 6345cdb..6c5559c 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -18,15 +18,19 @@
import static com.google.gerrit.server.project.ProjectCache.noSuchProject;
import com.google.common.collect.Streams;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.entities.SubmitTypeRecord;
import com.google.gerrit.exceptions.StorageException;
+import com.google.gerrit.extensions.api.changes.ChangeApi;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Description.Units;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.Timer0;
+import com.google.gerrit.server.change.ChangeJson;
import com.google.gerrit.server.index.OnlineReindexMode;
+import com.google.gerrit.server.logging.CallerFinder;
import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.rules.DefaultSubmitRule;
@@ -42,12 +46,15 @@
* the results through rules found in the parent projects, all the way up to All-Projects.
*/
public class SubmitRuleEvaluator {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
private final ProjectCache projectCache;
private final PrologRule prologRule;
private final PluginSetContext<SubmitRule> submitRules;
private final Timer0 submitRuleEvaluationLatency;
private final Timer0 submitTypeEvaluationLatency;
private final SubmitRuleOptions opts;
+ private final CallerFinder callerFinder;
public interface Factory {
/** Returns a new {@link SubmitRuleEvaluator} with the specified options */
@@ -78,6 +85,14 @@
.setUnit(Units.MILLISECONDS));
this.opts = options;
+
+ this.callerFinder =
+ CallerFinder.builder()
+ .addTarget(ChangeApi.class)
+ .addTarget(ChangeJson.class)
+ .addTarget(ChangeData.class)
+ .addTarget(SubmitRequirementsEvaluatorImpl.class)
+ .build();
}
/**
@@ -88,6 +103,9 @@
* @param cd ChangeData to evaluate
*/
public List<SubmitRecord> evaluate(ChangeData cd) {
+ logger.atFine().log(
+ "Evaluate submit rules for change %d (caller: %s)",
+ cd.change().getId().get(), callerFinder.findCallerLazy());
try (Timer0.Context ignored = submitRuleEvaluationLatency.start()) {
Change change;
ProjectState projectState;
@@ -125,7 +143,17 @@
projectState.hasPrologRules()
? rule -> !(rule.get() instanceof DefaultSubmitRule)
: rule -> true)
- .map(c -> c.call(s -> s.evaluate(cd)))
+ .map(
+ c ->
+ c.call(
+ s -> {
+ Optional<SubmitRecord> evaluate = s.evaluate(cd);
+ if (evaluate.isPresent()) {
+ evaluate.get().ruleName =
+ c.getPluginName() + "~" + s.getClass().getSimpleName();
+ }
+ return evaluate;
+ }))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toImmutableList());
@@ -136,7 +164,6 @@
* Evaluate the submit type rules to get the submit type.
*
* @return record from the evaluated rules.
- * @param cd
*/
public SubmitTypeRecord getSubmitType(ChangeData cd) {
try (Timer0.Context ignored = submitTypeEvaluationLatency.start()) {
diff --git a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
index b7f8b45..1d67009 100644
--- a/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
+++ b/java/com/google/gerrit/server/query/account/InternalAccountQuery.java
@@ -31,6 +31,7 @@
import com.google.gerrit.index.query.InternalQuery;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.index.account.AccountField;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.inject.Inject;
@@ -46,12 +47,16 @@
public class InternalAccountQuery extends InternalQuery<AccountState, InternalAccountQuery> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ private final ExternalIdKeyFactory externalIdKeyFactory;
+
@Inject
InternalAccountQuery(
AccountQueryProcessor queryProcessor,
AccountIndexCollection indexes,
- IndexConfig indexConfig) {
+ IndexConfig indexConfig,
+ ExternalIdKeyFactory externalIdKeyFactory) {
super(queryProcessor, indexes, indexConfig);
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
public List<AccountState> byDefault(String query, boolean canSeeSecondaryEmails) {
@@ -59,7 +64,7 @@
}
public List<AccountState> byExternalId(String scheme, String id) {
- return byExternalId(ExternalId.Key.create(scheme, id));
+ return byExternalId(externalIdKeyFactory.create(scheme, id));
}
public List<AccountState> byExternalId(ExternalId.Key externalId) {
diff --git a/java/com/google/gerrit/server/query/approval/ApprovalContext.java b/java/com/google/gerrit/server/query/approval/ApprovalContext.java
index 3bf072a..4dedbb5 100644
--- a/java/com/google/gerrit/server/query/approval/ApprovalContext.java
+++ b/java/com/google/gerrit/server/query/approval/ApprovalContext.java
@@ -28,8 +28,12 @@
/** Approval on the source patch set to be copied. */
public abstract PatchSetApproval patchSetApproval();
- /** Target change and patch set for the approval. */
- public abstract PatchSet.Id target();
+ /**
+ * Target change and patch set for the approval. This must be used instead of getting the PatchSet
+ * from {@link #changeNotes()} because it is possible we are now creating the patch-set, so it
+ * doesn't exist in changeNotes yet.
+ */
+ public abstract PatchSet target();
/** {@link ChangeNotes} of the change in question. */
public abstract ChangeNotes changeNotes();
@@ -38,18 +42,18 @@
public abstract ChangeKind changeKind();
public static ApprovalContext create(
- ChangeNotes changeNotes, PatchSetApproval psa, PatchSet.Id id, ChangeKind changeKind) {
+ ChangeNotes changeNotes, PatchSetApproval psa, PatchSet patchSet, ChangeKind changeKind) {
checkState(
- psa.patchSetId().changeId().equals(id.changeId()),
+ psa.patchSetId().changeId().equals(patchSet.id().changeId()),
"approval and target must be the same change. got: %s, %s",
psa.patchSetId(),
- id);
+ patchSet.id());
// TODO(ekempin): Use checkState to verify that psa.patchSetId().get() + 1 == id.get() so that
// it's ensured that approvals are only copied to the next consecutive patch set. To add back
// this verification https://gerrit-review.googlesource.com/c/gerrit/+/312633 can be reverted.
// As explained in the commit message of this change doing this check is only possible if there
// are no changes with gaps in patch set numbers. Since it's planned to fix-up old changes with
// gaps in patch set numbers, this todo is a reminder to add back the check once this is done.
- return new AutoValue_ApprovalContext(psa, id, changeNotes, changeKind);
+ return new AutoValue_ApprovalContext(psa, patchSet, changeNotes, changeKind);
}
}
diff --git a/java/com/google/gerrit/server/query/approval/ListOfFilesUnchangedPredicate.java b/java/com/google/gerrit/server/query/approval/ListOfFilesUnchangedPredicate.java
index 459a8b0..55c27be 100644
--- a/java/com/google/gerrit/server/query/approval/ListOfFilesUnchangedPredicate.java
+++ b/java/com/google/gerrit/server/query/approval/ListOfFilesUnchangedPredicate.java
@@ -14,40 +14,57 @@
package com.google.gerrit.server.query.approval;
+import com.google.gerrit.entities.Patch;
import com.google.gerrit.entities.Patch.ChangeType;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.patch.DiffNotAvailableException;
import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.io.IOException;
import java.util.Collection;
+import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevWalk;
/** Predicate that matches when the new patch-set includes the same files as the old patch-set. */
@Singleton
public class ListOfFilesUnchangedPredicate extends ApprovalPredicate {
private final DiffOperations diffOperations;
+ private final GitRepositoryManager repositoryManager;
@Inject
- public ListOfFilesUnchangedPredicate(DiffOperations diffOperations) {
+ public ListOfFilesUnchangedPredicate(
+ DiffOperations diffOperations, GitRepositoryManager repositoryManager) {
this.diffOperations = diffOperations;
+ this.repositoryManager = repositoryManager;
}
@Override
public boolean match(ApprovalContext ctx) {
- PatchSet currentPatchset = ctx.changeNotes().getCurrentPatchSet();
- Map.Entry<PatchSet.Id, PatchSet> priorPatchSet =
- ctx.changeNotes().getPatchSets().lowerEntry(currentPatchset.id());
+ PatchSet targetPatchSet = ctx.target();
+ PatchSet sourcePatchSet =
+ ctx.changeNotes().getPatchSets().get(ctx.patchSetApproval().patchSetId());
+
+ Integer parentNum =
+ isInitialCommit(ctx.changeNotes().getProjectName(), targetPatchSet.commitId()) ? 0 : 1;
try {
- return match(
- diffOperations.listModifiedFiles(
- ctx.changeNotes().getProjectName(),
- priorPatchSet.getValue().commitId(),
- currentPatchset.commitId()));
+ Map<String, FileDiffOutput> modifiedTargetPatchSet =
+ diffOperations.listModifiedFilesAgainstParent(
+ ctx.changeNotes().getProjectName(), targetPatchSet.commitId(), parentNum);
+ Map<String, FileDiffOutput> modifiedSourcePatchSet =
+ diffOperations.listModifiedFilesAgainstParent(
+ ctx.changeNotes().getProjectName(), sourcePatchSet.commitId(), parentNum);
+ return match(modifiedTargetPatchSet, modifiedSourcePatchSet);
} catch (DiffNotAvailableException ex) {
throw new StorageException(
"failed to compute difference in files, so won't copy"
@@ -57,24 +74,49 @@
}
}
- public boolean match(Map<String, FileDiffOutput> modifiedFiles) {
- return modifiedFiles.values().stream()
- .noneMatch(
- p ->
- p.changeType() == ChangeType.ADDED
- || p.changeType() == ChangeType.DELETED
- || p.changeType() == ChangeType.RENAMED);
+ /**
+ * returns {@code true} if the files that were modified are the same in both inputs, and the
+ * {@link ChangeType} matches for each modified file.
+ */
+ public boolean match(
+ Map<String, FileDiffOutput> modifiedFiles1, Map<String, FileDiffOutput> modifiedFiles2) {
+ Set<String> allFiles = new HashSet<>();
+ allFiles.addAll(modifiedFiles1.keySet());
+ allFiles.addAll(modifiedFiles2.keySet());
+ for (String file : allFiles) {
+ if (Patch.isMagic(file)) {
+ continue;
+ }
+ FileDiffOutput fileDiffOutput1 = modifiedFiles1.get(file);
+ FileDiffOutput fileDiffOutput2 = modifiedFiles2.get(file);
+ if (fileDiffOutput1 == null || fileDiffOutput2 == null) {
+ return false;
+ }
+ if (!fileDiffOutput2.changeType().equals(fileDiffOutput1.changeType())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isInitialCommit(Project.NameKey project, ObjectId objectId) {
+ try (Repository repo = repositoryManager.openRepository(project);
+ RevWalk revWalk = new RevWalk(repo)) {
+ return revWalk.parseCommit(objectId).getParentCount() == 0;
+ } catch (IOException ex) {
+ throw new StorageException(ex);
+ }
}
@Override
public Predicate<ApprovalContext> copy(
Collection<? extends Predicate<ApprovalContext>> children) {
- return new ListOfFilesUnchangedPredicate(diffOperations);
+ return new ListOfFilesUnchangedPredicate(diffOperations, repositoryManager);
}
@Override
public int hashCode() {
- return Objects.hash(diffOperations);
+ return Objects.hash(diffOperations, repositoryManager);
}
@Override
@@ -83,6 +125,7 @@
return false;
}
ListOfFilesUnchangedPredicate o = (ListOfFilesUnchangedPredicate) other;
- return Objects.equals(o.diffOperations, diffOperations);
+ return Objects.equals(o.diffOperations, diffOperations)
+ && Objects.equals(o.repositoryManager, repositoryManager);
}
}
diff --git a/java/com/google/gerrit/server/query/approval/UserInPredicate.java b/java/com/google/gerrit/server/query/approval/UserInPredicate.java
index 7e16fcb..ac6720d 100644
--- a/java/com/google/gerrit/server/query/approval/UserInPredicate.java
+++ b/java/com/google/gerrit/server/query/approval/UserInPredicate.java
@@ -39,7 +39,7 @@
public boolean match(ApprovalContext ctx) {
Account.Id accountId;
if (field == Field.UPLOADER) {
- PatchSet patchSet = ctx.changeNotes().getPatchSets().get(ctx.target());
+ PatchSet patchSet = ctx.target();
accountId = patchSet.uploader();
} else if (field == Field.APPROVER) {
accountId = ctx.patchSetApproval().accountId();
diff --git a/java/com/google/gerrit/server/query/change/ChangeData.java b/java/com/google/gerrit/server/query/change/ChangeData.java
index 8b4e4c7..6c74301 100644
--- a/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -728,7 +728,7 @@
this.attentionSet = attentionSet;
}
- /** @return patches for the change, in patch set ID order. */
+ /** Returns patches for the change, in patch set ID order. */
public Collection<PatchSet> patchSets() {
if (patchSets == null) {
patchSets = psUtil.byChange(notes());
@@ -741,7 +741,7 @@
this.patchSets = patchSets;
}
- /** @return patch with the given ID, or null if it does not exist. */
+ /** Returns patch with the given ID, or null if it does not exist. */
public PatchSet patchSet(PatchSet.Id psId) {
if (currentPatchSet != null && currentPatchSet.id().equals(psId)) {
return currentPatchSet;
@@ -755,8 +755,8 @@
}
/**
- * @return all patch set approvals for the change, keyed by ID, ordered by timestamp within each
- * patch set.
+ * Returns all patch set approvals for the change, keyed by ID, ordered by timestamp within each
+ * patch set.
*/
public ListMultimap<PatchSet.Id, PatchSetApproval> approvals() {
if (allApprovals == null) {
@@ -951,7 +951,7 @@
notes().getSubmitRequirementsResult().stream()
.collect(Collectors.toMap(r -> r.submitRequirement(), Function.identity()));
} else {
- submitRequirements = submitRequirementsEvaluator.getResults(this);
+ submitRequirements = submitRequirementsEvaluator.evaluateAllRequirements(this);
}
}
return submitRequirements;
@@ -1102,19 +1102,6 @@
}
public boolean isReviewedBy(Account.Id accountId) {
- Collection<String> stars = stars(accountId);
-
- PatchSet ps = currentPatchSet();
- if (ps != null) {
- if (stars.contains(StarredChangesUtil.REVIEWED_LABEL + "/" + ps.number())) {
- return true;
- }
-
- if (stars.contains(StarredChangesUtil.UNREVIEWED_LABEL + "/" + ps.number())) {
- return false;
- }
- }
-
return reviewedBy().contains(accountId);
}
@@ -1212,8 +1199,8 @@
}
/**
- * @return {@code null} if {@code revertOf} is {@code null}; true if the change is a pure revert;
- * false otherwise.
+ * Returns {@code null} if {@code revertOf} is {@code null}; true if the change is a pure revert;
+ * false otherwise.
*/
@Nullable
public Boolean isPureRevert() {
diff --git a/java/com/google/gerrit/server/query/change/ChangeDataSource.java b/java/com/google/gerrit/server/query/change/ChangeDataSource.java
index 34579a9..26ce46c 100644
--- a/java/com/google/gerrit/server/query/change/ChangeDataSource.java
+++ b/java/com/google/gerrit/server/query/change/ChangeDataSource.java
@@ -17,6 +17,6 @@
import com.google.gerrit.index.query.DataSource;
public interface ChangeDataSource extends DataSource<ChangeData> {
- /** @return true if all returned ChangeData.hasChange() will be true. */
+ /** Returns true if all returned ChangeData.hasChange() will be true. */
boolean hasChange();
}
diff --git a/java/com/google/gerrit/server/query/change/ChangePredicates.java b/java/com/google/gerrit/server/query/change/ChangePredicates.java
index 044d276..4e638df 100644
--- a/java/com/google/gerrit/server/query/change/ChangePredicates.java
+++ b/java/com/google/gerrit/server/query/change/ChangePredicates.java
@@ -292,4 +292,15 @@
public static Predicate<ChangeData> comment(String comment) {
return new ChangeIndexPredicate(ChangeField.COMMENT, comment);
}
+
+ /**
+ * Returns a predicate that matches with changes having a specific submit rule evaluating to a
+ * certain result. Value should be in the form of "$ruleName=$status" with $ruleName equals to
+ * '$plugin_name~$rule_name' and $rule_name equals to the name of the class that implements the
+ * {@link com.google.gerrit.server.rules.SubmitRule}. For gerrit core rules, $ruleName should be
+ * in the form of 'gerrit~$rule_name'.
+ */
+ public static Predicate<ChangeData> submitRuleStatus(String value) {
+ return new ChangeIndexPredicate(ChangeField.SUBMIT_RULE_RESULT, value);
+ }
}
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 383e385..f1fe520 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -78,8 +78,10 @@
import com.google.gerrit.server.notedb.ReviewerStateInternal;
import com.google.gerrit.server.patch.PatchListCache;
import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ChildProjects;
import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.rules.SubmitRule;
import com.google.gerrit.server.submit.SubmitDryRun;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -87,6 +89,7 @@
import com.google.inject.util.Providers;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -139,6 +142,7 @@
public static final String FIELD_ADDED = "added";
public static final String FIELD_AGE = "age";
public static final String FIELD_ATTENTION_SET_USERS = "attentionusers";
+ public static final String FIELD_ATTENTION_SET_USERS_COUNT = "attentionuserscount";
public static final String FIELD_ATTENTION_SET_FULL = "attentionfull";
public static final String FIELD_ASSIGNEE = "assignee";
public static final String FIELD_AUTHOR = "author";
@@ -176,7 +180,6 @@
public static final String FIELD_OWNERIN = "ownerin";
public static final String FIELD_PARENTOF = "parentof";
public static final String FIELD_PARENTPROJECT = "parentproject";
- public static final String FIELD_PATH = "path";
public static final String FIELD_PENDING_REVIEWER = "pendingreviewer";
public static final String FIELD_PENDING_REVIEWER_BY_EMAIL = "pendingreviewerbyemail";
public static final String FIELD_PRIVATE = "private";
@@ -184,11 +187,9 @@
public static final String FIELD_PROJECTS = "projects";
public static final String FIELD_REF = "ref";
public static final String FIELD_REVIEWEDBY = "reviewedby";
- public static final String FIELD_REVIEWER = "reviewer";
public static final String FIELD_REVIEWERIN = "reviewerin";
public static final String FIELD_STAR = "star";
public static final String FIELD_STARBY = "starby";
- public static final String FIELD_STARREDBY = "starredby";
public static final String FIELD_STARTED = "started";
public static final String FIELD_STATUS = "status";
public static final String FIELD_SUBMISSIONID = "submissionid";
@@ -198,7 +199,7 @@
public static final String FIELD_WATCHEDBY = "watchedby";
public static final String FIELD_WIP = "wip";
public static final String FIELD_REVERTOF = "revertof";
- public static final String FIELD_CHERRY_PICK_OF = "cherrypickof";
+ public static final String FIELD_CHERRYPICK = "cherrypick";
public static final String FIELD_CHERRY_PICK_OF_CHANGE = "cherrypickofchange";
public static final String FIELD_CHERRY_PICK_OF_PATCHSET = "cherrypickofpatchset";
@@ -206,7 +207,9 @@
public static final String ARG_ID_USER = "user";
public static final String ARG_ID_GROUP = "group";
public static final String ARG_ID_OWNER = "owner";
+ public static final String ARG_ID_NON_UPLOADER = "non_uploader";
public static final Account.Id OWNER_ACCOUNT_ID = Account.id(0);
+ public static final Account.Id NON_UPLOADER_ACCOUNT_ID = Account.id(-1);
public static final String OPERATOR_MERGED_BEFORE = "mergedbefore";
public static final String OPERATOR_MERGED_AFTER = "mergedafter";
@@ -249,6 +252,7 @@
final boolean indexMergeable;
final boolean conflictsPredicateEnabled;
final HasOperandAliasConfig hasOperandAliasConfig;
+ final PluginSetContext<SubmitRule> submitRules;
private final Provider<CurrentUser> self;
@@ -283,7 +287,8 @@
OperatorAliasConfig operatorAliasConfig,
@GerritServerConfig Config gerritConfig,
HasOperandAliasConfig hasOperandAliasConfig,
- ChangeIsVisibleToPredicate.Factory changeIsVisbleToPredicateFactory) {
+ ChangeIsVisibleToPredicate.Factory changeIsVisbleToPredicateFactory,
+ PluginSetContext<SubmitRule> submitRules) {
this(
queryProvider,
rewriter,
@@ -314,7 +319,8 @@
MergeabilityComputationBehavior.fromConfig(gerritConfig).includeInIndex(),
gerritConfig.getBoolean("change", null, "conflictsPredicateEnabled", true),
hasOperandAliasConfig,
- changeIsVisbleToPredicateFactory);
+ changeIsVisbleToPredicateFactory,
+ submitRules);
}
private Arguments(
@@ -347,7 +353,8 @@
boolean indexMergeable,
boolean conflictsPredicateEnabled,
HasOperandAliasConfig hasOperandAliasConfig,
- ChangeIsVisibleToPredicate.Factory changeIsVisbleToPredicateFactory) {
+ ChangeIsVisibleToPredicate.Factory changeIsVisbleToPredicateFactory,
+ PluginSetContext<SubmitRule> submitRules) {
this.queryProvider = queryProvider;
this.rewriter = rewriter;
this.opFactories = opFactories;
@@ -378,6 +385,7 @@
this.indexMergeable = indexMergeable;
this.conflictsPredicateEnabled = conflictsPredicateEnabled;
this.hasOperandAliasConfig = hasOperandAliasConfig;
+ this.submitRules = submitRules;
}
Arguments asUser(CurrentUser otherUser) {
@@ -411,7 +419,8 @@
indexMergeable,
conflictsPredicateEnabled,
hasOperandAliasConfig,
- changeIsVisbleToPredicateFactory);
+ changeIsVisbleToPredicateFactory,
+ submitRules);
}
Arguments asUser(Account.Id otherId) {
@@ -471,10 +480,6 @@
hasOperandAliases = args.hasOperandAliasConfig.getChangeQueryHasOperandAliases();
}
- public Arguments getArgs() {
- return args;
- }
-
public ChangeQueryBuilder asUser(CurrentUser user) {
return new ChangeQueryBuilder(builderDef, args.asUser(user));
}
@@ -567,24 +572,57 @@
}
@Operator
+ public Predicate<ChangeData> rule(String value) throws QueryParseException {
+ String ruleNameArg = value;
+ String statusArg = null;
+ String[] queryArgs = value.split("=");
+ if (queryArgs.length > 2) {
+ throw new QueryParseException(
+ "Invalid query arguments. Correct format is 'rule:<rule_name>=<status>' "
+ + "with <rule_name> in the form of <plugin>~<rule>. For Gerrit core rules, "
+ + "rule name should be specified either as gerrit~<rule> or <rule>.");
+ }
+ if (queryArgs.length == 2) {
+ ruleNameArg = queryArgs[0];
+ statusArg = queryArgs[1];
+ }
+
+ // If ruleName is not prefixed by the plugin name, add the "gerrit~" prefix to it.
+ if (!ruleNameArg.contains("~")) {
+ ruleNameArg = "gerrit~" + ruleNameArg;
+ }
+
+ return statusArg == null
+ ? Predicate.or(
+ Arrays.asList(
+ ChangePredicates.submitRuleStatus(ruleNameArg + "=" + SubmitRecord.Status.OK),
+ ChangePredicates.submitRuleStatus(ruleNameArg + "=" + SubmitRecord.Status.FORCED)))
+ : ChangePredicates.submitRuleStatus(ruleNameArg + "=" + statusArg);
+ }
+
+ @Operator
public Predicate<ChangeData> has(String value) throws QueryParseException {
value = hasOperandAliases.getOrDefault(value, value);
if ("star".equalsIgnoreCase(value)) {
- return starredby(self());
- }
-
- if ("stars".equalsIgnoreCase(value)) {
- return new HasStarsPredicate(self());
+ return starredBySelf();
}
if ("draft".equalsIgnoreCase(value)) {
- return draftby(self());
+ return draftBySelf();
}
if ("edit".equalsIgnoreCase(value)) {
return ChangePredicates.editBy(self());
}
+ if ("attention".equalsIgnoreCase(value)) {
+ if (!args.index.getSchema().hasField(ChangeField.ATTENTION_SET_USERS)) {
+ throw new QueryParseException(
+ "'has:attention' operator is not supported by change index version");
+ }
+ return new IsAttentionPredicate();
+ }
+
if ("unresolved".equalsIgnoreCase(value)) {
return new IsUnresolvedPredicate();
}
@@ -604,11 +642,11 @@
@Operator
public Predicate<ChangeData> is(String value) throws QueryParseException {
if ("starred".equalsIgnoreCase(value)) {
- return starredby(self());
+ return starredBySelf();
}
if ("watched".equalsIgnoreCase(value)) {
- return new IsWatchedByPredicate(args, false);
+ return new IsWatchedByPredicate(args);
}
if ("visible".equalsIgnoreCase(value)) {
@@ -658,6 +696,14 @@
"'is:private' operator is not supported by change index version");
}
+ if ("attention".equalsIgnoreCase(value)) {
+ if (!args.index.getSchema().hasField(ChangeField.ATTENTION_SET_USERS)) {
+ throw new QueryParseException(
+ "'is:attention' operator is not supported by change index version");
+ }
+ return new IsAttentionPredicate();
+ }
+
if ("assigned".equalsIgnoreCase(value)) {
return Predicate.not(ChangePredicates.assignee(Account.id(ChangeField.NO_ASSIGNEE)));
}
@@ -679,7 +725,7 @@
}
if ("ignored".equalsIgnoreCase(value)) {
- return star("ignore");
+ return ignoredBySelf();
}
if ("started".equalsIgnoreCase(value)) {
@@ -697,6 +743,14 @@
throw new QueryParseException("'is:wip' operator is not supported by change index version");
}
+ if ("cherrypick".equalsIgnoreCase(value)) {
+ if (args.getSchema().hasField(ChangeField.CHERRY_PICK)) {
+ return new BooleanPredicate(ChangeField.CHERRY_PICK);
+ }
+ throw new QueryParseException(
+ "'is:cherrypick' operator is not supported by change index version");
+ }
+
// for plugins the value will be operandName_pluginName
List<String> names = Lists.newArrayList(Splitter.on('_').split(value));
if (names.size() == 2) {
@@ -940,6 +994,8 @@
if (pair.getKey().equalsIgnoreCase(ARG_ID_USER)) {
if (pair.getValue().equals(ARG_ID_OWNER)) {
accounts = Collections.singleton(OWNER_ACCOUNT_ID);
+ } else if (pair.getValue().equals(ARG_ID_NON_UPLOADER)) {
+ accounts = Collections.singleton(NON_UPLOADER_ACCOUNT_ID);
} else {
accounts = parseAccount(pair.getValue());
}
@@ -957,6 +1013,8 @@
try {
if (value.equals(ARG_ID_OWNER)) {
accounts = Collections.singleton(OWNER_ACCOUNT_ID);
+ } else if (value.equals(ARG_ID_NON_UPLOADER)) {
+ accounts = Collections.singleton(NON_UPLOADER_ACCOUNT_ID);
} else {
accounts = parseAccount(value);
}
@@ -1011,65 +1069,25 @@
@Operator
public Predicate<ChangeData> star(String label) throws QueryParseException {
- return new StarPredicate(self(), label);
- }
-
- @Operator
- public Predicate<ChangeData> starredby(String who)
- throws QueryParseException, IOException, ConfigInvalidException {
- return starredby(parseAccount(who));
- }
-
- private Predicate<ChangeData> starredby(Set<Account.Id> who) {
- List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(who.size());
- for (Account.Id id : who) {
- p.add(starredby(id));
+ if ("ignore".equalsIgnoreCase(label)) {
+ return ignoredBySelf();
}
- return Predicate.or(p);
- }
-
- private Predicate<ChangeData> starredby(Account.Id who) {
- return new StarPredicate(who, StarredChangesUtil.DEFAULT_LABEL);
- }
-
- @Operator
- public Predicate<ChangeData> watchedby(String who)
- throws QueryParseException, IOException, ConfigInvalidException {
- Set<Account.Id> m = parseAccount(who);
- List<IsWatchedByPredicate> p = Lists.newArrayListWithCapacity(m.size());
-
- Account.Id callerId;
- try {
- CurrentUser caller = args.self.get();
- callerId = caller.isIdentifiedUser() ? caller.getAccountId() : null;
- } catch (ProvisionException e) {
- callerId = null;
+ if ("star".equalsIgnoreCase(label)) {
+ return starredBySelf();
}
-
- for (Account.Id id : m) {
- // Each child IsWatchedByPredicate includes a visibility filter for the
- // corresponding user, to ensure that predicate subtree only returns
- // changes visible to that user. The exception is if one of the users is
- // the caller of this method, in which case visibility is already being
- // checked at the top level.
- p.add(new IsWatchedByPredicate(args.asUser(id), !id.equals(callerId)));
- }
- return Predicate.or(p);
+ throw new IllegalArgumentException();
}
- @Operator
- public Predicate<ChangeData> draftby(String who)
- throws QueryParseException, IOException, ConfigInvalidException {
- Set<Account.Id> m = parseAccount(who);
- List<Predicate<ChangeData>> p = Lists.newArrayListWithCapacity(m.size());
- for (Account.Id id : m) {
- p.add(draftby(id));
- }
- return Predicate.or(p);
+ private Predicate<ChangeData> ignoredBySelf() throws QueryParseException {
+ return new StarPredicate(self(), StarredChangesUtil.IGNORE_LABEL);
}
- private Predicate<ChangeData> draftby(Account.Id who) {
- return ChangePredicates.draftBy(who);
+ private Predicate<ChangeData> starredBySelf() throws QueryParseException {
+ return new StarPredicate(self(), StarredChangesUtil.DEFAULT_LABEL);
+ }
+
+ private Predicate<ChangeData> draftBySelf() throws QueryParseException {
+ return ChangePredicates.draftBy(self());
}
@Operator
@@ -1539,6 +1557,12 @@
private Predicate<ChangeData> getAuthorOrCommitterFullTextPredicate(
String who, Function<String, Predicate<ChangeData>> fullPredicateFunc)
throws QueryParseException {
+ if (isSelf(who)) {
+ IdentifiedUser me = args.getIdentifiedUser();
+ List<Predicate<ChangeData>> predicates =
+ me.getEmailAddresses().stream().map(fullPredicateFunc).collect(toList());
+ return Predicate.or(predicates);
+ }
Set<String> parts = SchemaUtil.getNameParts(who);
if (parts.isEmpty()) {
throw error("invalid value");
diff --git a/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java b/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
index ade615c..12efecb 100644
--- a/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
+++ b/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
@@ -108,16 +108,23 @@
return false;
}
- if (account != null
- && !account.equals(approver)
- && !account.equals(ChangeQueryBuilder.OWNER_ACCOUNT_ID)) {
- return false;
- }
+ if (account != null) {
+ // case when account in query is numeric
+ if (!account.equals(approver) && !isMagicUser()) {
+ return false;
+ }
- if (account != null
- && account.equals(ChangeQueryBuilder.OWNER_ACCOUNT_ID)
- && !cd.change().getOwner().equals(approver)) {
- return false;
+ // case when account in query = owner
+ if (account.equals(ChangeQueryBuilder.OWNER_ACCOUNT_ID)
+ && !cd.change().getOwner().equals(approver)) {
+ return false;
+ }
+
+ // case when account in query = non_uploader
+ if (account.equals(ChangeQueryBuilder.NON_UPLOADER_ACCOUNT_ID)
+ && cd.currentPatchSet().uploader().equals(approver)) {
+ return false;
+ }
}
IdentifiedUser reviewer = userFactory.create(approver);
@@ -139,6 +146,11 @@
}
}
+ private boolean isMagicUser() {
+ return account.equals(ChangeQueryBuilder.OWNER_ACCOUNT_ID)
+ || account.equals(ChangeQueryBuilder.NON_UPLOADER_ACCOUNT_ID);
+ }
+
@Override
public int getCost() {
return 1 + (group == null ? 0 : 1);
diff --git a/java/com/google/gerrit/server/query/change/HasStarsPredicate.java b/java/com/google/gerrit/server/query/change/HasStarsPredicate.java
deleted file mode 100644
index 6482a19..0000000
--- a/java/com/google/gerrit/server/query/change/HasStarsPredicate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright (C) 2016 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.query.change;
-
-import com.google.gerrit.entities.Account;
-import com.google.gerrit.server.index.change.ChangeField;
-
-public class HasStarsPredicate extends ChangeIndexPredicate {
- protected final Account.Id accountId;
-
- public HasStarsPredicate(Account.Id accountId) {
- super(ChangeField.STARBY, accountId.toString());
- this.accountId = accountId;
- }
-
- @Override
- public boolean match(ChangeData cd) {
- return cd.stars().containsKey(accountId);
- }
-
- @Override
- public String toString() {
- return ChangeQueryBuilder.FIELD_STARBY + ":" + accountId;
- }
-}
diff --git a/java/com/google/gerrit/server/query/change/IsAttentionPredicate.java b/java/com/google/gerrit/server/query/change/IsAttentionPredicate.java
new file mode 100644
index 0000000..d20d64a
--- /dev/null
+++ b/java/com/google/gerrit/server/query/change/IsAttentionPredicate.java
@@ -0,0 +1,33 @@
+// 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.query.change;
+
+import com.google.gerrit.index.query.QueryParseException;
+import com.google.gerrit.server.index.change.ChangeField;
+
+public class IsAttentionPredicate extends IntegerRangeChangePredicate {
+ public IsAttentionPredicate() throws QueryParseException {
+ this(">0");
+ }
+
+ public IsAttentionPredicate(String value) throws QueryParseException {
+ super(ChangeField.ATTENTION_SET_USERS_COUNT, value);
+ }
+
+ @Override
+ protected Integer getValueInt(ChangeData changeData) {
+ return ChangeField.ATTENTION_SET_USERS_COUNT.get(changeData);
+ }
+}
diff --git a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
index 3a43fd3..054a69e 100644
--- a/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
+++ b/java/com/google/gerrit/server/query/change/IsWatchedByPredicate.java
@@ -36,14 +36,13 @@
protected final CurrentUser user;
- public IsWatchedByPredicate(ChangeQueryBuilder.Arguments args, boolean checkIsVisible)
- throws QueryParseException {
- super(filters(args, checkIsVisible));
+ public IsWatchedByPredicate(ChangeQueryBuilder.Arguments args) throws QueryParseException {
+ super(filters(args));
this.user = args.getUser();
}
- protected static List<Predicate<ChangeData>> filters(
- ChangeQueryBuilder.Arguments args, boolean checkIsVisible) throws QueryParseException {
+ protected static List<Predicate<ChangeData>> filters(ChangeQueryBuilder.Arguments args)
+ throws QueryParseException {
List<Predicate<ChangeData>> r = new ArrayList<>();
ChangeQueryBuilder builder = new ChangeQueryBuilder(args);
for (ProjectWatchKey w : getWatches(args)) {
@@ -82,11 +81,8 @@
}
if (r.isEmpty()) {
return ImmutableList.of(ChangeIndexPredicate.none());
- } else if (checkIsVisible) {
- return ImmutableList.of(or(r), builder.isVisible());
- } else {
- return ImmutableList.of(or(r));
}
+ return ImmutableList.of(or(r));
}
protected static Collection<ProjectWatchKey> getWatches(ChangeQueryBuilder.Arguments args)
diff --git a/java/com/google/gerrit/server/query/change/LabelPredicate.java b/java/com/google/gerrit/server/query/change/LabelPredicate.java
index 989b4bb..5f017fb 100644
--- a/java/com/google/gerrit/server/query/change/LabelPredicate.java
+++ b/java/com/google/gerrit/server/query/change/LabelPredicate.java
@@ -87,7 +87,7 @@
try {
MagicLabelVote mlv = MagicLabelVote.parseWithEquals(v);
- return ImmutableList.of(new MagicLabelPredicate(args, mlv));
+ return ImmutableList.of(magicLabelPredicate(args, mlv));
} catch (IllegalArgumentException e) {
// Try next format.
}
@@ -157,6 +157,17 @@
return or(r);
}
+ protected static Predicate<ChangeData> magicLabelPredicate(Args args, MagicLabelVote mlv) {
+ if (args.accounts == null || args.accounts.isEmpty()) {
+ return new MagicLabelPredicate(args, mlv, /* account= */ null);
+ }
+ List<Predicate<ChangeData>> r = new ArrayList<>();
+ for (Account.Id a : args.accounts) {
+ r.add(new MagicLabelPredicate(args, mlv, a));
+ }
+ return or(r);
+ }
+
@Override
public String toString() {
return ChangeQueryBuilder.FIELD_LABEL + ":" + value;
diff --git a/java/com/google/gerrit/server/query/change/MagicLabelPredicate.java b/java/com/google/gerrit/server/query/change/MagicLabelPredicate.java
index 2c56322..3917c79 100644
--- a/java/com/google/gerrit/server/query/change/MagicLabelPredicate.java
+++ b/java/com/google/gerrit/server/query/change/MagicLabelPredicate.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.query.change;
+import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.LabelTypes;
@@ -28,9 +29,12 @@
public class MagicLabelPredicate extends ChangeIndexPredicate {
protected final LabelPredicate.Args args;
private final MagicLabelVote magicLabelVote;
+ private final Account.Id account;
- public MagicLabelPredicate(LabelPredicate.Args args, MagicLabelVote magicLabelVote) {
+ public MagicLabelPredicate(
+ LabelPredicate.Args args, MagicLabelVote magicLabelVote, Account.Id account) {
super(ChangeField.LABEL, magicLabelVote.formatLabel());
+ this.account = account;
this.args = args;
this.magicLabelVote = magicLabelVote;
}
@@ -83,7 +87,7 @@
}
private EqualsLabelPredicate numericPredicate(String label, short value) {
- return new EqualsLabelPredicate(args, label, value, /* account= */ null);
+ return new EqualsLabelPredicate(args, label, value, account);
}
protected static LabelType type(LabelTypes types, String toFind) {
diff --git a/java/com/google/gerrit/server/query/change/PredicateArgs.java b/java/com/google/gerrit/server/query/change/PredicateArgs.java
index ad7917e..d82b9bc 100644
--- a/java/com/google/gerrit/server/query/change/PredicateArgs.java
+++ b/java/com/google/gerrit/server/query/change/PredicateArgs.java
@@ -40,7 +40,6 @@
* name]}.
*
* @param args arguments to be parsed
- * @throws QueryParseException
*/
PredicateArgs(String args) throws QueryParseException {
positional = new ArrayList<>();
diff --git a/java/com/google/gerrit/server/restapi/BUILD b/java/com/google/gerrit/server/restapi/BUILD
index 6d3e222..f70379b 100644
--- a/java/com/google/gerrit/server/restapi/BUILD
+++ b/java/com/google/gerrit/server/restapi/BUILD
@@ -33,6 +33,7 @@
"//lib/auto:auto-value-annotations",
"//lib/commons:compress",
"//lib/commons:lang",
+ "//lib/errorprone:annotations",
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-assistedinject",
diff --git a/java/com/google/gerrit/server/restapi/account/CreateAccount.java b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
index baa2951..b4946c4 100644
--- a/java/com/google/gerrit/server/restapi/account/CreateAccount.java
+++ b/java/com/google/gerrit/server/restapi/account/CreateAccount.java
@@ -44,6 +44,7 @@
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.group.GroupResolver;
import com.google.gerrit.server.group.db.GroupDelta;
@@ -85,6 +86,7 @@
private final Provider<GroupsUpdate> groupsUpdate;
private final OutgoingEmailValidator validator;
private final AuthConfig authConfig;
+ private final ExternalIdFactory externalIdFactory;
@Inject
CreateAccount(
@@ -97,7 +99,8 @@
PluginSetContext<AccountExternalIdCreator> externalIdCreators,
@UserInitiated Provider<GroupsUpdate> groupsUpdate,
OutgoingEmailValidator validator,
- AuthConfig authConfig) {
+ AuthConfig authConfig,
+ ExternalIdFactory externalIdFactory) {
this.seq = seq;
this.groupResolver = groupResolver;
this.authorizedKeys = authorizedKeys;
@@ -108,6 +111,7 @@
this.groupsUpdate = groupsUpdate;
this.validator = validator;
this.authConfig = authConfig;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -142,10 +146,10 @@
if (!validator.isValid(input.email)) {
throw new BadRequestException("invalid email address");
}
- extIds.add(ExternalId.createEmail(accountId, input.email));
+ extIds.add(externalIdFactory.createEmail(accountId, input.email));
}
- extIds.add(ExternalId.createUsername(username, accountId, input.httpPassword));
+ extIds.add(externalIdFactory.createUsername(username, accountId, input.httpPassword));
externalIdCreators.runEach(c -> extIds.addAll(c.create(accountId, username, input.email)));
try {
diff --git a/java/com/google/gerrit/server/restapi/account/CreateEmail.java b/java/com/google/gerrit/server/restapi/account/CreateEmail.java
index 6ee4539..70fbb26 100644
--- a/java/com/google/gerrit/server/restapi/account/CreateEmail.java
+++ b/java/com/google/gerrit/server/restapi/account/CreateEmail.java
@@ -83,6 +83,7 @@
private final OutgoingEmailValidator validator;
private final MessageIdGenerator messageIdGenerator;
private final boolean isDevMode;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
CreateEmail(
@@ -94,7 +95,8 @@
RegisterNewEmailSender.Factory registerNewEmailFactory,
PutPreferred putPreferred,
OutgoingEmailValidator validator,
- MessageIdGenerator messageIdGenerator) {
+ MessageIdGenerator messageIdGenerator,
+ AuthRequest.Factory authRequestFactory) {
this.self = self;
this.realm = realm;
this.permissionBackend = permissionBackend;
@@ -104,6 +106,7 @@
this.validator = validator;
this.isDevMode = authConfig.getAuthType() == DEVELOPMENT_BECOME_ANY_ACCOUNT;
this.messageIdGenerator = messageIdGenerator;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -151,7 +154,7 @@
logger.atWarning().log("skipping email validation in developer mode");
}
try {
- accountManager.link(user.getAccountId(), AuthRequest.forEmail(email));
+ accountManager.link(user.getAccountId(), authRequestFactory.createForEmail(email));
} catch (AccountException e) {
throw new ResourceConflictException(e.getMessage());
}
diff --git a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
index 445a5d6..e099a70 100644
--- a/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
+++ b/java/com/google/gerrit/server/restapi/account/DeleteExternalIds.java
@@ -18,6 +18,8 @@
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.Response;
@@ -29,6 +31,7 @@
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -56,17 +59,20 @@
private final AccountManager accountManager;
private final ExternalIds externalIds;
private final Provider<CurrentUser> self;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
DeleteExternalIds(
PermissionBackend permissionBackend,
AccountManager accountManager,
ExternalIds externalIds,
- Provider<CurrentUser> self) {
+ Provider<CurrentUser> self,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.permissionBackend = permissionBackend;
this.accountManager = accountManager;
this.externalIds = externalIds;
this.self = self;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -87,15 +93,24 @@
List<ExternalId> toDelete = new ArrayList<>();
Optional<ExternalId.Key> last = resource.getUser().getLastLoginExternalIdKey();
for (String externalIdStr : extIds) {
- ExternalId id = externalIdMap.get(ExternalId.Key.parse(externalIdStr));
+ ExternalId id = externalIdMap.get(externalIdKeyFactory.parse(externalIdStr));
if (id == null) {
throw new UnprocessableEntityException(
String.format("External id %s does not exist", externalIdStr));
}
- if ((!id.isScheme(SCHEME_USERNAME))
- && (!last.isPresent() || (!last.get().equals(id.key())))) {
+ if (!last.isPresent() || !last.get().equals(id.key())) {
+ if (id.isScheme(SCHEME_USERNAME)) {
+ if (self.get().hasSameAccountId(resource.getUser())) {
+ throw new AuthException("User cannot delete its own externalId in 'username:' scheme");
+ }
+ permissionBackend
+ .currentUser()
+ .checkAny(
+ ImmutableSet.of(
+ GlobalPermission.ADMINISTRATE_SERVER, GlobalPermission.MAINTAIN_SERVER));
+ }
toDelete.add(id);
} else {
throw new ResourceConflictException(
diff --git a/java/com/google/gerrit/server/restapi/account/Module.java b/java/com/google/gerrit/server/restapi/account/Module.java
index 7570465..dd38ccf 100644
--- a/java/com/google/gerrit/server/restapi/account/Module.java
+++ b/java/com/google/gerrit/server/restapi/account/Module.java
@@ -99,10 +99,6 @@
delete(STARRED_CHANGE_KIND).to(StarredChanges.Delete.class);
bind(StarredChanges.Create.class);
- child(ACCOUNT_KIND, "stars.changes").to(Stars.class);
- get(STAR_KIND).to(Stars.Get.class);
- post(STAR_KIND).to(Stars.Post.class);
-
get(ACCOUNT_KIND, "external.ids").to(GetExternalIds.class);
post(ACCOUNT_KIND, "external.ids:delete").to(DeleteExternalIds.class);
diff --git a/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java b/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
index 2427def..9361e27 100644
--- a/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
+++ b/java/com/google/gerrit/server/restapi/account/PutHttpPassword.java
@@ -34,6 +34,8 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.mail.send.HttpPasswordUpdateSender;
import com.google.gerrit.server.permissions.GlobalPermission;
@@ -77,6 +79,8 @@
private final ExternalIds externalIds;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PutHttpPassword(
@@ -84,12 +88,16 @@
PermissionBackend permissionBackend,
ExternalIds externalIds,
@UserInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory) {
+ HttpPasswordUpdateSender.Factory httpPasswordUpdateSenderFactory,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.httpPasswordUpdateSenderFactory = httpPasswordUpdateSenderFactory;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -125,7 +133,7 @@
String userName =
user.getUserName().orElseThrow(() -> new ResourceConflictException("username must be set"));
Optional<ExternalId> optionalExtId =
- externalIds.get(ExternalId.Key.create(SCHEME_USERNAME, userName));
+ externalIds.get(externalIdKeyFactory.create(SCHEME_USERNAME, userName));
ExternalId extId = optionalExtId.orElseThrow(ResourceNotFoundException::new);
accountsUpdateProvider
.get()
@@ -134,7 +142,7 @@
extId.accountId(),
u ->
u.updateExternalId(
- ExternalId.createWithPassword(
+ externalIdFactory.createWithPassword(
extId.key(), extId.accountId(), extId.email(), newPassword)));
try {
diff --git a/java/com/google/gerrit/server/restapi/account/PutPreferred.java b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
index 32b5ff2..aee0b78 100644
--- a/java/com/google/gerrit/server/restapi/account/PutPreferred.java
+++ b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
@@ -30,6 +30,7 @@
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -62,17 +63,20 @@
private final PermissionBackend permissionBackend;
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final ExternalIds externalIds;
+ private final ExternalIdFactory externalIdFactory;
@Inject
PutPreferred(
Provider<CurrentUser> self,
PermissionBackend permissionBackend,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
- ExternalIds externalIds) {
+ ExternalIds externalIds,
+ ExternalIdFactory externalIdFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.accountsUpdateProvider = accountsUpdateProvider;
this.externalIds = externalIds;
+ this.externalIdFactory = externalIdFactory;
}
@Override
@@ -137,7 +141,8 @@
}
// claim the email now
- u.addExternalId(ExternalId.createEmail(a.account().id(), preferredEmail));
+ u.addExternalId(
+ externalIdFactory.createEmail(a.account().id(), preferredEmail));
matchingEmail = preferredEmail;
} else {
// Realm says that the email doesn't belong to the user. This can only happen as
diff --git a/java/com/google/gerrit/server/restapi/account/PutUsername.java b/java/com/google/gerrit/server/restapi/account/PutUsername.java
index 05bf1fd..f295389 100644
--- a/java/com/google/gerrit/server/restapi/account/PutUsername.java
+++ b/java/com/google/gerrit/server/restapi/account/PutUsername.java
@@ -34,6 +34,8 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -65,6 +67,8 @@
private final Provider<AccountsUpdate> accountsUpdateProvider;
private final SshKeyCache sshKeyCache;
private final Realm realm;
+ private final ExternalIdFactory externalIdFactory;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
PutUsername(
@@ -73,13 +77,17 @@
ExternalIds externalIds,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider,
SshKeyCache sshKeyCache,
- Realm realm) {
+ Realm realm,
+ ExternalIdFactory externalIdFactory,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.self = self;
this.permissionBackend = permissionBackend;
this.externalIds = externalIds;
this.accountsUpdateProvider = accountsUpdateProvider;
this.sshKeyCache = sshKeyCache;
this.realm = realm;
+ this.externalIdFactory = externalIdFactory;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -107,14 +115,14 @@
throw new UnprocessableEntityException("invalid username");
}
- ExternalId.Key key = ExternalId.Key.create(SCHEME_USERNAME, input.username);
+ ExternalId.Key key = externalIdKeyFactory.create(SCHEME_USERNAME, input.username);
try {
accountsUpdateProvider
.get()
.update(
"Set Username via API",
accountId,
- u -> u.addExternalId(ExternalId.create(key, accountId, null, null)));
+ u -> u.addExternalId(externalIdFactory.create(key, accountId, null, null)));
} catch (DuplicateKeyException dupeErr) {
// If we are using this identity, don't report the exception.
Optional<ExternalId> other = externalIds.get(key);
diff --git a/java/com/google/gerrit/server/restapi/account/StarredChanges.java b/java/com/google/gerrit/server/restapi/account/StarredChanges.java
index e67fe9e..39c1fef 100644
--- a/java/com/google/gerrit/server/restapi/account/StarredChanges.java
+++ b/java/com/google/gerrit/server/restapi/account/StarredChanges.java
@@ -90,7 +90,7 @@
return (RestReadView<AccountResource>)
self -> {
QueryChanges query = changes.list();
- query.addQuery("starredby:" + self.getUser().getAccountId().get());
+ query.addQuery("has:star");
return query.apply(TopLevelResource.INSTANCE);
};
}
diff --git a/java/com/google/gerrit/server/restapi/account/Stars.java b/java/com/google/gerrit/server/restapi/account/Stars.java
deleted file mode 100644
index cc362f2..0000000
--- a/java/com/google/gerrit/server/restapi/account/Stars.java
+++ /dev/null
@@ -1,183 +0,0 @@
-// Copyright (C) 2016 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.restapi.account;
-
-import com.google.gerrit.extensions.api.changes.StarsInput;
-import com.google.gerrit.extensions.common.ChangeInfo;
-import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.extensions.restapi.ChildCollection;
-import com.google.gerrit.extensions.restapi.IdString;
-import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.extensions.restapi.TopLevelResource;
-import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.StarredChangesUtil;
-import com.google.gerrit.server.StarredChangesUtil.IllegalLabelException;
-import com.google.gerrit.server.account.AccountResource;
-import com.google.gerrit.server.account.AccountResource.Star;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.permissions.PermissionBackendException;
-import com.google.gerrit.server.restapi.change.ChangesCollection;
-import com.google.gerrit.server.restapi.change.QueryChanges;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import java.io.IOException;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-
-/**
- * Implements adding label stars to changes.
- *
- * <p>This handles {@code POST} and {@code GET} for {@code
- * /accounts/<account-identifier>/stars.changes/<change ID>}.
- */
-@Singleton
-public class Stars implements ChildCollection<AccountResource, AccountResource.Star> {
-
- private final ChangesCollection changes;
- private final ListStarredChanges listStarredChanges;
- private final StarredChangesUtil starredChangesUtil;
- private final DynamicMap<RestView<AccountResource.Star>> views;
-
- @Inject
- Stars(
- ChangesCollection changes,
- ListStarredChanges listStarredChanges,
- StarredChangesUtil starredChangesUtil,
- DynamicMap<RestView<AccountResource.Star>> views) {
- this.changes = changes;
- this.listStarredChanges = listStarredChanges;
- this.starredChangesUtil = starredChangesUtil;
- this.views = views;
- }
-
- @Override
- public Star parse(AccountResource parent, IdString id)
- throws RestApiException, PermissionBackendException, IOException {
- IdentifiedUser user = parent.getUser();
- // This enforces visibility of the change.
- ChangeResource change = changes.parse(TopLevelResource.INSTANCE, id);
- Set<String> labels = starredChangesUtil.getLabels(user.getAccountId(), change.getId());
- return new AccountResource.Star(user, change, labels);
- }
-
- @Override
- public DynamicMap<RestView<Star>> views() {
- return views;
- }
-
- @Override
- public ListStarredChanges list() {
- return listStarredChanges;
- }
-
- @Singleton
- public static class ListStarredChanges implements RestReadView<AccountResource> {
-
- private final Provider<CurrentUser> self;
- private final ChangesCollection changes;
-
- @Inject
- ListStarredChanges(Provider<CurrentUser> self, ChangesCollection changes) {
- this.self = self;
- this.changes = changes;
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public Response<List<ChangeInfo>> apply(AccountResource rsrc)
- throws RestApiException, PermissionBackendException {
- if (!self.get().hasSameAccountId(rsrc.getUser())) {
- throw new AuthException("not allowed to list stars of another account");
- }
-
- // The type of the value in the response that is returned by QueryChanges depends on the
- // number of queries that is provided as input. If a single query is provided as input the
- // value type is {@code List<ChangeInfo>}, if multiple queries are provided as input the value
- // type is {@code List<List<ChangeInfo>>) (one {@code List<ChangeInfo>} as result to each
- // query). Since in this case we provide exactly one query ("has:stars") as input we know that
- // the value always has the type {@code List<ChangeInfo>} and hence we can safely cast the
- // value to this type.
- QueryChanges query = changes.list();
- query.addQuery("has:stars");
- Response<?> response = query.apply(TopLevelResource.INSTANCE);
- List<ChangeInfo> value = (List<ChangeInfo>) response.value();
- return Response.ok(value);
- }
- }
-
- @Singleton
- public static class Get implements RestReadView<AccountResource.Star> {
-
- private final Provider<CurrentUser> self;
- private final StarredChangesUtil starredChangesUtil;
-
- @Inject
- Get(Provider<CurrentUser> self, StarredChangesUtil starredChangesUtil) {
- this.self = self;
- this.starredChangesUtil = starredChangesUtil;
- }
-
- @Override
- public Response<SortedSet<String>> apply(AccountResource.Star rsrc) throws AuthException {
- if (!self.get().hasSameAccountId(rsrc.getUser())) {
- throw new AuthException("not allowed to get stars of another account");
- }
- return Response.ok(
- starredChangesUtil.getLabels(self.get().getAccountId(), rsrc.getChange().getId()));
- }
- }
-
- @Singleton
- public static class Post implements RestModifyView<AccountResource.Star, StarsInput> {
-
- private final Provider<CurrentUser> self;
- private final StarredChangesUtil starredChangesUtil;
-
- @Inject
- Post(Provider<CurrentUser> self, StarredChangesUtil starredChangesUtil) {
- this.self = self;
- this.starredChangesUtil = starredChangesUtil;
- }
-
- @Override
- public Response<Collection<String>> apply(AccountResource.Star rsrc, StarsInput in)
- throws AuthException, BadRequestException {
- if (!self.get().hasSameAccountId(rsrc.getUser())) {
- throw new AuthException("not allowed to update stars of another account");
- }
- try {
- return Response.ok(
- starredChangesUtil.star(
- self.get().getAccountId(),
- rsrc.getChange().getProject(),
- rsrc.getChange().getId(),
- in.add,
- in.remove));
- } catch (IllegalLabelException e) {
- throw new BadRequestException(e.getMessage());
- }
- }
- }
-}
diff --git a/java/com/google/gerrit/server/restapi/change/ChangeIncludedIn.java b/java/com/google/gerrit/server/restapi/change/ChangeIncludedIn.java
index 67b5870..517fbdf 100644
--- a/java/com/google/gerrit/server/restapi/change/ChangeIncludedIn.java
+++ b/java/com/google/gerrit/server/restapi/change/ChangeIncludedIn.java
@@ -22,6 +22,7 @@
import com.google.gerrit.server.PatchSetUtil;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.IncludedIn;
+import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -38,7 +39,8 @@
}
@Override
- public Response<IncludedInInfo> apply(ChangeResource rsrc) throws RestApiException, IOException {
+ public Response<IncludedInInfo> apply(ChangeResource rsrc)
+ throws RestApiException, IOException, PermissionBackendException {
PatchSet ps = psUtil.current(rsrc.getNotes());
return Response.ok(includedIn.apply(rsrc.getProject(), ps.commitId().name()));
}
diff --git a/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java b/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java
deleted file mode 100644
index fa4555b..0000000
--- a/java/com/google/gerrit/server/restapi/change/MarkAsReviewed.java
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (C) 2017 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.restapi.change;
-
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.extensions.common.Input;
-import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestApiException;
-import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.webui.UiAction;
-import com.google.gerrit.server.StarredChangesUtil;
-import com.google.gerrit.server.StarredChangesUtil.IllegalLabelException;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.query.change.ChangeData;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class MarkAsReviewed
- implements RestModifyView<ChangeResource, Input>, UiAction<ChangeResource> {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final ChangeData.Factory changeDataFactory;
- private final StarredChangesUtil stars;
-
- @Inject
- MarkAsReviewed(ChangeData.Factory changeDataFactory, StarredChangesUtil stars) {
- this.changeDataFactory = changeDataFactory;
- this.stars = stars;
- }
-
- @Override
- public Description getDescription(ChangeResource rsrc) {
- return new UiAction.Description()
- .setLabel("Mark Reviewed")
- .setTitle("Mark the change as reviewed to unhighlight it in the dashboard")
- .setVisible(!isReviewed(rsrc));
- }
-
- @Override
- public Response<String> apply(ChangeResource rsrc, Input input)
- throws RestApiException, IllegalLabelException {
- stars.markAsReviewed(rsrc);
- return Response.ok();
- }
-
- private boolean isReviewed(ChangeResource rsrc) {
- try {
- return changeDataFactory
- .create(rsrc.getNotes())
- .isReviewedBy(rsrc.getUser().asIdentifiedUser().getAccountId());
- } catch (StorageException e) {
- logger.atSevere().withCause(e).log("failed to check if change is reviewed");
- }
- return false;
- }
-}
diff --git a/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java b/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java
deleted file mode 100644
index 601fc4a..0000000
--- a/java/com/google/gerrit/server/restapi/change/MarkAsUnreviewed.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (C) 2017 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.restapi.change;
-
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.extensions.common.Input;
-import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.webui.UiAction;
-import com.google.gerrit.server.StarredChangesUtil;
-import com.google.gerrit.server.StarredChangesUtil.IllegalLabelException;
-import com.google.gerrit.server.change.ChangeResource;
-import com.google.gerrit.server.query.change.ChangeData;
-import com.google.inject.Inject;
-import com.google.inject.Singleton;
-
-@Singleton
-public class MarkAsUnreviewed
- implements RestModifyView<ChangeResource, Input>, UiAction<ChangeResource> {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final ChangeData.Factory changeDataFactory;
- private final StarredChangesUtil stars;
-
- @Inject
- MarkAsUnreviewed(ChangeData.Factory changeDataFactory, StarredChangesUtil stars) {
- this.changeDataFactory = changeDataFactory;
- this.stars = stars;
- }
-
- @Override
- public Description getDescription(ChangeResource rsrc) {
- return new UiAction.Description()
- .setLabel("Mark Unreviewed")
- .setTitle("Mark the change as unreviewed to highlight it in the dashboard")
- .setVisible(isReviewed(rsrc));
- }
-
- @Override
- public Response<String> apply(ChangeResource rsrc, Input input) throws IllegalLabelException {
- stars.markAsUnreviewed(rsrc);
- return Response.ok();
- }
-
- private boolean isReviewed(ChangeResource rsrc) {
- try {
- return changeDataFactory
- .create(rsrc.getNotes())
- .isReviewedBy(rsrc.getUser().asIdentifiedUser().getAccountId());
- } catch (StorageException e) {
- logger.atSevere().withCause(e).log("failed to check if change is reviewed");
- }
- return false;
- }
-}
diff --git a/java/com/google/gerrit/server/restapi/change/Module.java b/java/com/google/gerrit/server/restapi/change/Module.java
index f87c9a1..000a17e 100644
--- a/java/com/google/gerrit/server/restapi/change/Module.java
+++ b/java/com/google/gerrit/server/restapi/change/Module.java
@@ -120,8 +120,6 @@
delete(CHANGE_KIND, "private").to(DeletePrivate.class);
put(CHANGE_KIND, "ignore").to(Ignore.class);
put(CHANGE_KIND, "unignore").to(Unignore.class);
- put(CHANGE_KIND, "reviewed").to(MarkAsReviewed.class);
- put(CHANGE_KIND, "unreviewed").to(MarkAsUnreviewed.class);
post(CHANGE_KIND, "wip").to(SetWorkInProgress.class);
post(CHANGE_KIND, "ready").to(SetReadyForReview.class);
put(CHANGE_KIND, "message").to(PutMessage.class);
diff --git a/java/com/google/gerrit/server/restapi/change/PostReview.java b/java/com/google/gerrit/server/restapi/change/PostReview.java
index 4dbb6ee..5002a82 100644
--- a/java/com/google/gerrit/server/restapi/change/PostReview.java
+++ b/java/com/google/gerrit/server/restapi/change/PostReview.java
@@ -80,6 +80,10 @@
import com.google.gerrit.extensions.validators.CommentValidationContext;
import com.google.gerrit.extensions.validators.CommentValidationFailure;
import com.google.gerrit.extensions.validators.CommentValidator;
+import com.google.gerrit.metrics.Counter1;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CommentsUtil;
@@ -151,6 +155,29 @@
public class PostReview implements RestModifyView<RevisionResource, ReviewInput> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ @Singleton
+ private static class Metrics {
+ final Counter1<String> draftHandling;
+
+ @Inject
+ Metrics(MetricMaker metricMaker) {
+ draftHandling =
+ metricMaker.newCounter(
+ "change/post_review/draft_handling",
+ new Description(
+ "Total number of draft handling option "
+ + "(KEEP, PUBLISH, PUBLISH_ALL_REVISIONS) "
+ + "selected by users while posting a review.")
+ .setRate()
+ .setUnit("count"),
+ Field.ofString("type", Metadata.Builder::eventType)
+ .description(
+ "The type of the draft handling option"
+ + " (KEEP, PUBLISH, PUBLISH_ALL_REVISIONS).")
+ .build());
+ }
+ }
+
private static final String ERROR_ADDING_REVIEWER = "error adding reviewer";
public static final String ERROR_WIP_READY_MUTUALLY_EXCLUSIVE =
"work_in_progress and ready are mutually exclusive";
@@ -170,6 +197,7 @@
private final EmailReviewComments.Factory email;
private final CommentAdded commentAdded;
private final ReviewerModifier reviewerModifier;
+ private final Metrics metrics;
private final ModifyReviewersEmail modifyReviewersEmail;
private final NotifyResolver notifyResolver;
private final WorkInProgressOp.Factory workInProgressOpFactory;
@@ -196,6 +224,7 @@
EmailReviewComments.Factory email,
CommentAdded commentAdded,
ReviewerModifier reviewerModifier,
+ Metrics metrics,
ModifyReviewersEmail modifyReviewersEmail,
NotifyResolver notifyResolver,
@GerritServerConfig Config gerritConfig,
@@ -218,6 +247,7 @@
this.email = email;
this.commentAdded = commentAdded;
this.reviewerModifier = reviewerModifier;
+ this.metrics = metrics;
this.modifyReviewersEmail = modifyReviewersEmail;
this.notifyResolver = notifyResolver;
this.workInProgressOpFactory = workInProgressOpFactory;
@@ -252,6 +282,7 @@
logger.atFine().log("strict label checking is %s", (strictLabels ? "enabled" : "disabled"));
+ metrics.draftHandling.increment(input.drafts == null ? "N/A" : input.drafts.name());
input.drafts = firstNonNull(input.drafts, DraftHandling.KEEP);
logger.atFine().log("draft handling = %s", input.drafts);
diff --git a/java/com/google/gerrit/server/restapi/change/RelatedChangesSorter.java b/java/com/google/gerrit/server/restapi/change/RelatedChangesSorter.java
index 1d550f1..0634081 100644
--- a/java/com/google/gerrit/server/restapi/change/RelatedChangesSorter.java
+++ b/java/com/google/gerrit/server/restapi/change/RelatedChangesSorter.java
@@ -19,6 +19,7 @@
import static java.util.stream.Collectors.toMap;
import com.google.auto.value.AutoValue;
+import com.google.auto.value.extension.memoized.Memoized;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap;
@@ -266,8 +267,9 @@
return psId().changeId();
}
+ @Memoized
@Override
- public final int hashCode() {
+ public int hashCode() {
return Objects.hash(patchSet().id(), commit());
}
diff --git a/java/com/google/gerrit/server/restapi/group/AddMembers.java b/java/com/google/gerrit/server/restapi/group/AddMembers.java
index f44abec..4cb2f47 100644
--- a/java/com/google/gerrit/server/restapi/group/AddMembers.java
+++ b/java/com/google/gerrit/server/restapi/group/AddMembers.java
@@ -94,6 +94,7 @@
private final AccountCache accountCache;
private final AccountLoader.Factory infoFactory;
private final Provider<GroupsUpdate> groupsUpdateProvider;
+ private final AuthRequest.Factory authRequestFactory;
@Inject
AddMembers(
@@ -102,13 +103,15 @@
AccountResolver accountResolver,
AccountCache accountCache,
AccountLoader.Factory infoFactory,
- @UserInitiated Provider<GroupsUpdate> groupsUpdateProvider) {
+ @UserInitiated Provider<GroupsUpdate> groupsUpdateProvider,
+ AuthRequest.Factory authRequestFactory) {
this.accountManager = accountManager;
this.authType = authConfig.getAuthType();
this.accountResolver = accountResolver;
this.accountCache = accountCache;
this.infoFactory = infoFactory;
this.groupsUpdateProvider = groupsUpdateProvider;
+ this.authRequestFactory = authRequestFactory;
}
@Override
@@ -190,7 +193,7 @@
}
try {
- AuthRequest req = AuthRequest.forUser(user);
+ AuthRequest req = authRequestFactory.createForUser(user);
req.setSkipAuthentication(true);
return accountCache
.get(accountManager.authenticate(req).getAccountId())
diff --git a/java/com/google/gerrit/server/restapi/project/CheckAccess.java b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
index 37616cd..5c2f932 100644
--- a/java/com/google/gerrit/server/restapi/project/CheckAccess.java
+++ b/java/com/google/gerrit/server/restapi/project/CheckAccess.java
@@ -95,7 +95,6 @@
} catch (AuthException e) {
return Response.ok(
createInfo(
- traceContext,
HttpServletResponse.SC_FORBIDDEN,
String.format("user %s cannot see project %s", match, rsrc.getName())));
}
@@ -126,7 +125,6 @@
} catch (AuthException e) {
return Response.ok(
createInfo(
- traceContext,
HttpServletResponse.SC_FORBIDDEN,
String.format(
"user %s lacks permission %s for %s in project %s",
@@ -141,15 +139,15 @@
}
}
}
- return Response.ok(createInfo(traceContext, HttpServletResponse.SC_OK, message));
+ return Response.ok(createInfo(HttpServletResponse.SC_OK, message));
}
}
- private AccessCheckInfo createInfo(TraceContext traceContext, int statusCode, String message) {
+ private AccessCheckInfo createInfo(int statusCode, String message) {
AccessCheckInfo info = new AccessCheckInfo();
info.status = statusCode;
info.message = message;
- info.debugLogs = traceContext.getAclLogRecords();
+ info.debugLogs = TraceContext.getAclLogRecords();
if (info.debugLogs.isEmpty()) {
info.debugLogs =
ImmutableList.of("Found no rules that apply, so defaulting to no permission");
diff --git a/java/com/google/gerrit/server/restapi/project/CommitIncludedIn.java b/java/com/google/gerrit/server/restapi/project/CommitIncludedIn.java
index a4a82ce..e566858 100644
--- a/java/com/google/gerrit/server/restapi/project/CommitIncludedIn.java
+++ b/java/com/google/gerrit/server/restapi/project/CommitIncludedIn.java
@@ -20,6 +20,7 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.change.IncludedIn;
+import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.CommitResource;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -36,7 +37,8 @@
}
@Override
- public Response<IncludedInInfo> apply(CommitResource rsrc) throws RestApiException, IOException {
+ public Response<IncludedInInfo> apply(CommitResource rsrc)
+ throws RestApiException, IOException, PermissionBackendException {
RevCommit commit = rsrc.getCommit();
Project.NameKey project = rsrc.getProjectState().getNameKey();
return Response.ok(includedIn.apply(project, commit.getId().getName()));
diff --git a/java/com/google/gerrit/server/restapi/project/CommitsCollection.java b/java/com/google/gerrit/server/restapi/project/CommitsCollection.java
index ae7f540..09951b2 100644
--- a/java/com/google/gerrit/server/restapi/project/CommitsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/CommitsCollection.java
@@ -116,14 +116,14 @@
}
/**
- * @return true if {@code commit} is visible to the caller and {@code commit} is reachable from
- * the given branch.
+ * Returns true if {@code commit} is visible to the caller and {@code commit} is reachable from
+ * the given branch.
*/
public boolean canRead(ProjectState state, Repository repo, RevCommit commit, Ref ref) {
return reachable.fromRefs(state.getNameKey(), repo, commit, ImmutableList.of(ref));
}
- /** @return true if {@code commit} is visible to the caller. */
+ /** Returns true if {@code commit} is visible to the caller. */
public boolean canRead(ProjectState state, Repository repo, RevCommit commit) throws IOException {
Project.NameKey project = state.getNameKey();
if (indexes.getSearchIndex() == null) {
diff --git a/java/com/google/gerrit/server/restapi/project/DeleteRef.java b/java/com/google/gerrit/server/restapi/project/DeleteRef.java
index 4e13ba9..60405a6 100644
--- a/java/com/google/gerrit/server/restapi/project/DeleteRef.java
+++ b/java/com/google/gerrit/server/restapi/project/DeleteRef.java
@@ -86,8 +86,6 @@
*
* @param projectState the {@code ProjectState} of the project containing the target ref.
* @param ref the ref to be deleted.
- * @throws IOException
- * @throws ResourceConflictException
*/
public void deleteSingleRef(ProjectState projectState, String ref)
throws IOException, ResourceConflictException, AuthException, PermissionBackendException {
@@ -100,8 +98,6 @@
* @param projectState the {@code ProjectState} of the project containing the target ref.
* @param ref the ref to be deleted.
* @param prefix the prefix of the ref.
- * @throws IOException
- * @throws ResourceConflictException
*/
public void deleteSingleRef(ProjectState projectState, String ref, @Nullable String prefix)
throws IOException, ResourceConflictException, AuthException, PermissionBackendException {
@@ -161,9 +157,6 @@
* @param projectState the {@code ProjectState} of the project whose refs are to be deleted.
* @param refsToDelete the refs to be deleted.
* @param prefix the prefix to add to abbreviated refs, eg. "refs/heads/".
- * @throws IOException
- * @throws ResourceConflictException
- * @throws PermissionBackendException
*/
public void deleteMultipleRefs(
ProjectState projectState, ImmutableSet<String> refsToDelete, String prefix)
diff --git a/java/com/google/gerrit/server/restapi/project/IndexChanges.java b/java/com/google/gerrit/server/restapi/project/IndexChanges.java
index 73a064c..6ad0005 100644
--- a/java/com/google/gerrit/server/restapi/project/IndexChanges.java
+++ b/java/com/google/gerrit/server/restapi/project/IndexChanges.java
@@ -24,9 +24,9 @@
import com.google.gerrit.extensions.common.Input;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.experiments.ExperimentFeatures;
import com.google.gerrit.server.git.MultiProgressMonitor;
import com.google.gerrit.server.git.MultiProgressMonitor.Task;
+import com.google.gerrit.server.git.MultiProgressMonitor.TaskKind;
import com.google.gerrit.server.index.IndexExecutor;
import com.google.gerrit.server.index.change.AllChangesIndexer;
import com.google.gerrit.server.index.change.ChangeIndexer;
@@ -41,18 +41,18 @@
@Singleton
public class IndexChanges implements RestModifyView<ProjectResource, Input> {
- private final ExperimentFeatures experimentFeatures;
+ private final MultiProgressMonitor.Factory multiProgressMonitorFactory;
private final Provider<AllChangesIndexer> allChangesIndexerProvider;
private final ChangeIndexer indexer;
private final ListeningExecutorService executor;
@Inject
IndexChanges(
- ExperimentFeatures experimentFeatures,
+ MultiProgressMonitor.Factory multiProgressMonitorFactory,
Provider<AllChangesIndexer> allChangesIndexerProvider,
ChangeIndexer indexer,
@IndexExecutor(BATCH) ListeningExecutorService executor) {
- this.experimentFeatures = experimentFeatures;
+ this.multiProgressMonitorFactory = multiProgressMonitorFactory;
this.allChangesIndexerProvider = allChangesIndexerProvider;
this.indexer = indexer;
this.executor = executor;
@@ -62,8 +62,8 @@
public Response.Accepted apply(ProjectResource resource, Input input) {
Project.NameKey project = resource.getNameKey();
Task mpt =
- new MultiProgressMonitor(
- experimentFeatures, ByteStreams.nullOutputStream(), "Reindexing project")
+ multiProgressMonitorFactory
+ .create(ByteStreams.nullOutputStream(), TaskKind.INDEXING, "Reindexing project")
.beginSubTask("", MultiProgressMonitor.UNKNOWN);
AllChangesIndexer allChangesIndexer = allChangesIndexerProvider.get();
allChangesIndexer.setVerboseOut(NullOutputStream.INSTANCE);
diff --git a/java/com/google/gerrit/server/restapi/project/ListProjects.java b/java/com/google/gerrit/server/restapi/project/ListProjects.java
index c4ae33a..4d8005b 100644
--- a/java/com/google/gerrit/server/restapi/project/ListProjects.java
+++ b/java/com/google/gerrit/server/restapi/project/ListProjects.java
@@ -490,7 +490,7 @@
continue;
}
- List<Ref> refs = retrieveBranchRefs(e);
+ List<Ref> refs = retrieveBranchRefs(e, git);
if (!hasValidRef(refs)) {
continue;
}
@@ -578,17 +578,12 @@
}
}
- private List<Ref> retrieveBranchRefs(ProjectState e) throws PermissionBackendException {
- boolean canReadAllRefs = e.statePermitsRead();
- if (canReadAllRefs) {
- try {
- permissionBackend.user(currentUser).project(e.getNameKey()).check(ProjectPermission.READ);
- } catch (AuthException exp) {
- canReadAllRefs = false;
- }
+ private List<Ref> retrieveBranchRefs(ProjectState e, Repository git) {
+ if (!e.statePermitsRead()) {
+ return ImmutableList.of();
}
- return getBranchRefs(e.getNameKey(), canReadAllRefs);
+ return getBranchRefs(e.getNameKey(), git);
}
private void addParentProjectInfo(
@@ -708,15 +703,13 @@
stdout.flush();
}
- private List<Ref> getBranchRefs(Project.NameKey projectName, boolean canReadAllRefs) {
+ private List<Ref> getBranchRefs(Project.NameKey projectName, Repository git) {
Ref[] result = new Ref[showBranch.size()];
- try (Repository git = repoManager.openRepository(projectName)) {
+ try {
PermissionBackend.ForProject perm = permissionBackend.user(currentUser).project(projectName);
for (int i = 0; i < showBranch.size(); i++) {
Ref ref = git.findRef(showBranch.get(i));
- if (all && canReadAllRefs) {
- result[i] = ref;
- } else if (ref != null && ref.getObjectId() != null) {
+ if (ref != null && ref.getObjectId() != null) {
try {
perm.ref(ref.getLeaf().getName()).check(RefPermission.READ);
result[i] = ref;
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index efc739c..6174798 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -105,7 +105,6 @@
* @throws RestApiException thrown if the project ID cannot be resolved or if the project is not
* visible to the calling user
* @throws IOException thrown when there is an error.
- * @throws PermissionBackendException
*/
public ProjectResource parse(String id)
throws RestApiException, IOException, PermissionBackendException {
@@ -121,7 +120,6 @@
* @throws RestApiException thrown if the project ID cannot be resolved or if the project is not
* visible to the calling user and checkVisibility is true.
* @throws IOException thrown when there is an error.
- * @throws PermissionBackendException
*/
public ProjectResource parse(String id, boolean checkAccess)
throws RestApiException, IOException, PermissionBackendException {
diff --git a/java/com/google/gerrit/server/rules/PrologEnvironment.java b/java/com/google/gerrit/server/rules/PrologEnvironment.java
index 7d626da..bc0bb1a 100644
--- a/java/com/google/gerrit/server/rules/PrologEnvironment.java
+++ b/java/com/google/gerrit/server/rules/PrologEnvironment.java
@@ -22,7 +22,7 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.patch.PatchListCache;
+import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectCache;
@@ -173,7 +173,7 @@
private final PermissionBackend permissionBackend;
private final GitRepositoryManager repositoryManager;
private final PluginConfigFactory pluginConfigFactory;
- private final PatchListCache patchListCache;
+ private final DiffOperations diffOperations;
private final PatchSetInfoFactory patchSetInfoFactory;
private final IdentifiedUser.GenericFactory userFactory;
private final Provider<AnonymousUser> anonymousUser;
@@ -188,7 +188,7 @@
PermissionBackend permissionBackend,
GitRepositoryManager repositoryManager,
PluginConfigFactory pluginConfigFactory,
- PatchListCache patchListCache,
+ DiffOperations diffOperations,
PatchSetInfoFactory patchSetInfoFactory,
IdentifiedUser.GenericFactory userFactory,
Provider<AnonymousUser> anonymousUser,
@@ -199,7 +199,7 @@
this.permissionBackend = permissionBackend;
this.repositoryManager = repositoryManager;
this.pluginConfigFactory = pluginConfigFactory;
- this.patchListCache = patchListCache;
+ this.diffOperations = diffOperations;
this.patchSetInfoFactory = patchSetInfoFactory;
this.userFactory = userFactory;
this.anonymousUser = anonymousUser;
@@ -237,8 +237,8 @@
return pluginConfigFactory;
}
- public PatchListCache getPatchListCache() {
- return patchListCache;
+ public DiffOperations getDiffOperations() {
+ return diffOperations;
}
public PatchSetInfoFactory getPatchSetInfoFactory() {
diff --git a/java/com/google/gerrit/server/rules/StoredValues.java b/java/com/google/gerrit/server/rules/StoredValues.java
index 1e08a24..1d10c1f 100644
--- a/java/com/google/gerrit/server/rules/StoredValues.java
+++ b/java/com/google/gerrit/server/rules/StoredValues.java
@@ -21,7 +21,6 @@
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.exceptions.StorageException;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchSetUtil;
@@ -30,10 +29,9 @@
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.PatchListNotAvailableException;
+import com.google.gerrit.server.patch.DiffNotAvailableException;
+import com.google.gerrit.server.patch.DiffOperations;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
@@ -87,24 +85,27 @@
}
};
- public static final StoredValue<PatchList> PATCH_LIST =
- new StoredValue<PatchList>() {
+ public static final StoredValue<Map<String, FileDiffOutput>> DIFF_LIST =
+ new StoredValue<Map<String, FileDiffOutput>>() {
@Override
- public PatchList createValue(Prolog engine) {
+ public Map<String, FileDiffOutput> createValue(Prolog engine) {
PrologEnvironment env = (PrologEnvironment) engine.control;
PatchSet ps = getPatchSet(engine);
- PatchListCache plCache = env.getArgs().getPatchListCache();
+ DiffOperations diffOperations = env.getArgs().getDiffOperations();
Change change = getChange(engine);
Project.NameKey project = change.getProject();
- Whitespace ws = Whitespace.IGNORE_NONE;
- PatchListKey plKey = PatchListKey.againstDefaultBase(ps.commitId(), ws);
- PatchList patchList;
+ Map<String, FileDiffOutput> diffList;
try {
- patchList = plCache.get(plKey, project);
- } catch (PatchListNotAvailableException e) {
- throw new SystemException(String.format("Cannot create %s: %s", plKey, e.getMessage()));
+ diffList =
+ diffOperations.listModifiedFilesAgainstParent(
+ project, ps.commitId(), /* parentNum= */ 0);
+ } catch (DiffNotAvailableException e) {
+ throw new SystemException(
+ String.format(
+ "Cannot create modified files for project %s, commit Id %s: %s",
+ project, ps.commitId(), e.getMessage()));
}
- return patchList;
+ return diffList;
}
};
diff --git a/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java b/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java
index 868e7ea..3bf9d02 100644
--- a/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java
+++ b/java/com/google/gerrit/server/schema/ProjectConfigSchemaUpdate.java
@@ -18,12 +18,11 @@
import static java.util.stream.Collectors.toList;
import com.google.common.annotations.VisibleForTesting;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.PermissionRule;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.exceptions.StorageException;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.git.meta.VersionedMetaData;
import com.google.gerrit.server.project.ProjectConfig;
@@ -31,6 +30,7 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.CommitBuilder;
@@ -40,32 +40,30 @@
public class ProjectConfigSchemaUpdate extends VersionedMetaData {
public static class Factory {
- private final SitePaths sitePaths;
private final AllProjectsName allProjectsName;
+ private final AllProjectsConfigProvider allProjectsConfigProvider;
@Inject
- Factory(SitePaths sitePaths, AllProjectsName allProjectsName) {
- this.sitePaths = sitePaths;
+ Factory(AllProjectsName allProjectsName, AllProjectsConfigProvider allProjectsConfigProvider) {
this.allProjectsName = allProjectsName;
+ this.allProjectsConfigProvider = allProjectsConfigProvider;
}
ProjectConfigSchemaUpdate read(MetaDataUpdate update)
throws IOException, ConfigInvalidException {
ProjectConfigSchemaUpdate r =
- new ProjectConfigSchemaUpdate(
- update,
- ProjectConfig.Factory.getBaseConfig(sitePaths, allProjectsName, allProjectsName));
+ new ProjectConfigSchemaUpdate(update, allProjectsConfigProvider.get(allProjectsName));
r.load(update);
return r;
}
}
private final MetaDataUpdate update;
- @Nullable private final StoredConfig baseConfig;
+ private final Optional<StoredConfig> baseConfig;
private Config config;
private boolean updated;
- private ProjectConfigSchemaUpdate(MetaDataUpdate update, @Nullable StoredConfig baseConfig) {
+ private ProjectConfigSchemaUpdate(MetaDataUpdate update, Optional<StoredConfig> baseConfig) {
this.update = update;
this.baseConfig = baseConfig;
}
@@ -77,8 +75,8 @@
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
- if (baseConfig != null) {
- baseConfig.load();
+ if (baseConfig.isPresent()) {
+ baseConfig.get().load();
}
config = readConfig(ProjectConfig.PROJECT_CONFIG, baseConfig);
}
diff --git a/java/com/google/gerrit/server/securestore/SecureStore.java b/java/com/google/gerrit/server/securestore/SecureStore.java
index b5aebee..b53e38c 100644
--- a/java/com/google/gerrit/server/securestore/SecureStore.java
+++ b/java/com/google/gerrit/server/securestore/SecureStore.java
@@ -39,13 +39,7 @@
public final String section;
public final String subsection;
- /**
- * Creates EntryKey.
- *
- * @param section
- * @param subsection
- * @param name
- */
+ /** Creates EntryKey */
public EntryKey(String section, String subsection, String name) {
this.name = name;
this.section = section;
@@ -57,9 +51,6 @@
* Extract decrypted value of stored property from SecureStore or {@code null} when property was
* not found.
*
- * @param section
- * @param subsection
- * @param name
* @return decrypted String value or {@code null} if not found
*/
public final String get(String section, String subsection, String name) {
@@ -74,10 +65,6 @@
* Extract decrypted value of stored plugin config property from SecureStore or {@code null} when
* property was not found.
*
- * @param pluginName
- * @param section
- * @param subsection
- * @param name
* @return decrypted String value or {@code null} if not found
*/
public final String getForPlugin(
@@ -93,10 +80,6 @@
* Extract list of plugin config values from SecureStore and decrypt every value in that list, or
* {@code null} when property was not found.
*
- * @param pluginName
- * @param section
- * @param subsection
- * @param name
* @return decrypted list of string values or {@code null}
*/
public abstract String[] getListForPlugin(
@@ -106,9 +89,6 @@
* Extract list of values from SecureStore and decrypt every value in that list or {@code null}
* when property was not found.
*
- * @param section
- * @param subsection
- * @param name
* @return decrypted list of string values or {@code null}
*/
public abstract String[] getList(String section, String subsection, String name);
@@ -118,9 +98,6 @@
*
* <p>This method is responsible for encrypting value and storing it.
*
- * @param section
- * @param subsection
- * @param name
* @param value plain text value
*/
public final void set(String section, String subsection, String name, String value) {
@@ -132,26 +109,19 @@
*
* <p>This method is responsible for encrypting all values in the list and storing them.
*
- * @param section
- * @param subsection
- * @param name
* @param values list of plain text values
*/
public abstract void setList(String section, String subsection, String name, List<String> values);
/**
* Remove value for given {@code section}, {@code subsection} and {@code name} from SecureStore.
- *
- * @param section
- * @param subsection
- * @param name
*/
public abstract void unset(String section, String subsection, String name);
- /** @return list of stored entries. */
+ /** Returns list of stored entries. */
public abstract Iterable<EntryKey> list();
- /** @return <code>true</code> if currently loaded values are outdated */
+ /** Returns <code>true</code> if currently loaded values are outdated */
public abstract boolean isOutdated();
/** Reload the values */
diff --git a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
index f181c36..7d428eb 100644
--- a/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
+++ b/java/com/google/gerrit/server/submit/SubmitStrategyOp.java
@@ -521,32 +521,22 @@
}
}
- /**
- * @see #updateRepo(RepoContext)
- * @param ctx
- */
+ /** See {@link #updateRepo(RepoContext)} */
protected void updateRepoImpl(RepoContext ctx) throws Exception {}
/**
- * @see #updateChange(ChangeContext)
- * @param ctx
- * @return a new patch set if one was created by the submit strategy, or null if not.
+ * Returns a new patch set if one was created by the submit strategy, or null if not
+ *
+ * <p>See {@link #updateChange(ChangeContext)}
*/
protected PatchSet updateChangeImpl(ChangeContext ctx) throws Exception {
return null;
}
- /**
- * @see #postUpdate(PostUpdateContext)
- * @param ctx
- */
+ /** See {@link #postUpdate(PostUpdateContext)} */
protected void postUpdateImpl(PostUpdateContext ctx) throws Exception {}
- /**
- * Amend the commit with gitlink update
- *
- * @param commit
- */
+ /** Amend the commit with gitlink update */
protected CodeReviewCommit amendGitlink(CodeReviewCommit commit)
throws IntegrationConflictException {
if (!args.subscriptionGraph.hasSubscription(args.destBranch)) {
diff --git a/java/com/google/gerrit/server/tools/ToolsCatalog.java b/java/com/google/gerrit/server/tools/ToolsCatalog.java
index aaa366c..9c1483f 100644
--- a/java/com/google/gerrit/server/tools/ToolsCatalog.java
+++ b/java/com/google/gerrit/server/tools/ToolsCatalog.java
@@ -175,28 +175,28 @@
return type;
}
- /** @return the preferred UNIX file mode, e.g. {@code 0755}. */
+ /** Returns the preferred UNIX file mode, e.g. {@code 0755}. */
public int getMode() {
return mode;
}
- /** @return path of the entry, relative to the catalog root. */
+ /** Returns path of the entry, relative to the catalog root. */
public String getPath() {
return path;
}
- /** @return name of the entry, within its parent directory. */
+ /** Returns the name of the entry, within its parent directory. */
public String getName() {
final int s = path.lastIndexOf('/');
return s < 0 ? path : path.substring(s + 1);
}
- /** @return collection of entries below this one, if this is a directory. */
+ /** Returns collection of entries below this one, if this is a directory. */
public List<Entry> getChildren() {
return Collections.unmodifiableList(children);
}
- /** @return a copy of the file's contents. */
+ /** Returns a copy of the file's contents. */
public byte[] getBytes() {
byte[] data = read(getPath());
diff --git a/java/com/google/gerrit/server/update/ChainedReceiveCommands.java b/java/com/google/gerrit/server/update/ChainedReceiveCommands.java
index c223aec..99c72f2 100644
--- a/java/com/google/gerrit/server/update/ChainedReceiveCommands.java
+++ b/java/com/google/gerrit/server/update/ChainedReceiveCommands.java
@@ -118,7 +118,7 @@
}
}
- /** @return an unmodifiable view of commands. */
+ /** Returns an unmodifiable view of commands. */
public Map<String, ReceiveCommand> getCommands() {
return Collections.unmodifiableMap(commands);
}
diff --git a/java/com/google/gerrit/server/update/ChangeContext.java b/java/com/google/gerrit/server/update/ChangeContext.java
index 5a53e2a..aeabde4 100644
--- a/java/com/google/gerrit/server/update/ChangeContext.java
+++ b/java/com/google/gerrit/server/update/ChangeContext.java
@@ -69,7 +69,7 @@
*/
void deleteChange();
- /** @return change corresponding to {@link #getNotes()}. */
+ /** Returns change corresponding to {@link #getNotes()}. */
default Change getChange() {
return requireNonNull(getNotes().getChange());
}
diff --git a/java/com/google/gerrit/server/update/RepoContext.java b/java/com/google/gerrit/server/update/RepoContext.java
index 9faf628..66831cd 100644
--- a/java/com/google/gerrit/server/update/RepoContext.java
+++ b/java/com/google/gerrit/server/update/RepoContext.java
@@ -22,9 +22,9 @@
/** Context for performing the {@link BatchUpdateOp#updateRepo} phase. */
public interface RepoContext extends Context {
/**
- * @return inserter for writing to the repo. Callers should not flush; the walk returned by {@link
- * #getRevWalk()} is able to read back objects inserted by this inserter without flushing
- * first.
+ * Returns inserter for writing to the repo. Callers should not flush; the walk returned by {@link
+ * #getRevWalk()} is able to read back objects inserted by this inserter without flushing first.
+ *
* @throws IOException if an error occurred opening the repo.
*/
ObjectInserter getInserter() throws IOException;
diff --git a/java/com/google/gerrit/server/update/RetryHelper.java b/java/com/google/gerrit/server/update/RetryHelper.java
index b846662..7e6974c 100644
--- a/java/com/google/gerrit/server/update/RetryHelper.java
+++ b/java/com/google/gerrit/server/update/RetryHelper.java
@@ -121,7 +121,9 @@
@Inject
Metrics(MetricMaker metricMaker) {
Field<String> actionTypeField =
- Field.ofString("action_type", Metadata.Builder::actionType).build();
+ Field.ofString("action_type", Metadata.Builder::actionType)
+ .description("The type of the action that was retried.")
+ .build();
Field<String> operationNameField =
Field.ofString("operation_name", Metadata.Builder::operationName)
.description("The name of the operation that was retried.")
@@ -479,7 +481,7 @@
}
String cause = formatCause(t);
- if (!traceContext.isTracing()) {
+ if (!TraceContext.isTracing()) {
String traceId = "retry-on-failure-" + new RequestId();
traceContext.addTag(RequestId.Type.TRACE_ID, traceId).forceLogging();
logger.atWarning().withCause(t).log(
@@ -548,8 +550,8 @@
* @param retryer the retryer
* @param listener metric listener
* @return the result of executing the action
- * @throws Throwable any error or exception that made the action fail, callers are expected to
- * catch and inspect this Throwable to decide carefully whether it should be re-thrown
+ * @throws Exception any exception that made the action fail, callers are expected to catch and
+ * inspect this exception to decide carefully whether it should be re-thrown
*/
private <T> T executeWithTimeoutCount(
String actionType,
diff --git a/java/com/google/gerrit/server/update/RetryableAction.java b/java/com/google/gerrit/server/update/RetryableAction.java
index fbb643e..f79a849 100644
--- a/java/com/google/gerrit/server/update/RetryableAction.java
+++ b/java/com/google/gerrit/server/update/RetryableAction.java
@@ -57,6 +57,7 @@
PLUGIN_UPDATE,
REST_READ_REQUEST,
REST_WRITE_REQUEST,
+ SEND_EMAIL,
}
@FunctionalInterface
diff --git a/java/com/google/gerrit/server/util/AttentionSetEmail.java b/java/com/google/gerrit/server/util/AttentionSetEmail.java
index 56b1dda..48ddd31 100644
--- a/java/com/google/gerrit/server/util/AttentionSetEmail.java
+++ b/java/com/google/gerrit/server/util/AttentionSetEmail.java
@@ -56,6 +56,7 @@
}
private ExecutorService sendEmailsExecutor;
+ private AccountTemplateUtil accountTemplateUtil;
private AttentionSetSender sender;
private Context ctx;
private Change change;
@@ -67,6 +68,7 @@
@Inject
AttentionSetEmail(
@SendEmailExecutor ExecutorService executor,
+ AccountTemplateUtil accountTemplateUtil,
@Assisted AttentionSetSender sender,
@Assisted Context ctx,
@Assisted Change change,
@@ -74,6 +76,7 @@
@Assisted MessageIdGenerator.MessageId messageId,
@Assisted Account.Id attentionUserId) {
this.sendEmailsExecutor = executor;
+ this.accountTemplateUtil = accountTemplateUtil;
this.sender = sender;
this.ctx = ctx;
this.change = change;
@@ -97,7 +100,7 @@
}
sender.setNotify(ctx.getNotify(change.getId()));
sender.setAttentionSetUser(attentionUserId);
- sender.setReason(reason);
+ sender.setReason(accountTemplateUtil.replaceTemplates(reason));
sender.setMessageId(messageId);
sender.send();
} catch (Exception e) {
diff --git a/java/com/google/gerrit/server/util/RequestScopePropagator.java b/java/com/google/gerrit/server/util/RequestScopePropagator.java
index dc8a136..10c46fc 100644
--- a/java/com/google/gerrit/server/util/RequestScopePropagator.java
+++ b/java/com/google/gerrit/server/util/RequestScopePropagator.java
@@ -160,7 +160,11 @@
};
}
- /** @see #wrap(Callable) */
+ /**
+ * Ensures that the current request state is available when the passed in Callable is invoked
+ *
+ * <p>See {@link #wrap(Callable)}
+ */
protected abstract <T> Callable<T> wrapImpl(Callable<T> callable);
protected <T> Callable<T> context(RequestContext context, Callable<T> callable) {
diff --git a/java/com/google/gerrit/server/util/time/TimeUtil.java b/java/com/google/gerrit/server/util/time/TimeUtil.java
index 639d0a6..54ef305 100644
--- a/java/com/google/gerrit/server/util/time/TimeUtil.java
+++ b/java/com/google/gerrit/server/util/time/TimeUtil.java
@@ -20,6 +20,7 @@
import com.google.gerrit.server.util.git.DelegateSystemReader;
import java.sql.Timestamp;
import java.time.Instant;
+import java.util.concurrent.TimeUnit;
import java.util.function.LongSupplier;
import org.eclipse.jgit.util.SystemReader;
@@ -35,6 +36,10 @@
return currentMillisSupplier.getAsLong();
}
+ public static long nowNanos() {
+ return TimeUnit.NANOSECONDS.convert(TimeUtil.nowMs(), TimeUnit.MILLISECONDS);
+ }
+
public static Instant now() {
return Instant.ofEpochMilli(nowMs());
}
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 42aabfb..f1be04e 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -73,6 +73,7 @@
static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2;
public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3;
+ @SuppressWarnings("unused") // unused here, but triggers logic in EndOfOptionsHandler
@Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class)
private boolean endOfOptions;
diff --git a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
index d5f0ee8..628a050 100644
--- a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
+++ b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
@@ -22,6 +22,7 @@
import com.google.gerrit.server.account.AccountSshKey;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.logging.Metadata;
@@ -97,11 +98,16 @@
static class Loader extends CacheLoader<String, Iterable<SshKeyCacheEntry>> {
private final ExternalIds externalIds;
private final VersionedAuthorizedKeys.Accessor authorizedKeys;
+ private final ExternalIdKeyFactory externalIdKeyFactory;
@Inject
- Loader(ExternalIds externalIds, VersionedAuthorizedKeys.Accessor authorizedKeys) {
+ Loader(
+ ExternalIds externalIds,
+ VersionedAuthorizedKeys.Accessor authorizedKeys,
+ ExternalIdKeyFactory externalIdKeyFactory) {
this.externalIds = externalIds;
this.authorizedKeys = authorizedKeys;
+ this.externalIdKeyFactory = externalIdKeyFactory;
}
@Override
@@ -111,7 +117,7 @@
"Loading SSH keys for account with username",
Metadata.builder().username(username).build())) {
Optional<ExternalId> user =
- externalIds.get(ExternalId.Key.create(SCHEME_USERNAME, username));
+ externalIds.get(externalIdKeyFactory.create(SCHEME_USERNAME, username));
if (!user.isPresent()) {
return NO_SUCH_USER;
}
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index 616f7d1..7c96342 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -92,7 +92,7 @@
}
}
- /** @return true if a change in state has occurred */
+ /** Returns true if a change in state has occurred */
public boolean enableLogging() {
synchronized (lock) {
if (async == null) {
@@ -112,7 +112,7 @@
}
}
- /** @return true if a change in state has occurred */
+ /** Returns true if a change in state has occurred */
public boolean disableLogging() {
synchronized (lock) {
if (async != null) {
diff --git a/java/com/google/gerrit/sshd/SshSession.java b/java/com/google/gerrit/sshd/SshSession.java
index b39eaed..d545844 100644
--- a/java/com/google/gerrit/sshd/SshSession.java
+++ b/java/com/google/gerrit/sshd/SshSession.java
@@ -114,7 +114,7 @@
identity.setAccessPath(path);
}
- /** @return {@code true} if the authentication did not succeed. */
+ /** Returns {@code true} if the authentication did not succeed. */
boolean isAuthenticationError() {
return authError != null;
}
diff --git a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index 43a1670..0c286ca 100644
--- a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -15,6 +15,7 @@
package com.google.gerrit.sshd.commands;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
import com.google.gerrit.common.RawInputUtil;
@@ -36,6 +37,7 @@
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountResource;
import com.google.gerrit.server.account.AccountSshKey;
+import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -43,6 +45,7 @@
import com.google.gerrit.server.restapi.account.CreateEmail;
import com.google.gerrit.server.restapi.account.DeleteActive;
import com.google.gerrit.server.restapi.account.DeleteEmail;
+import com.google.gerrit.server.restapi.account.DeleteExternalIds;
import com.google.gerrit.server.restapi.account.DeleteSshKey;
import com.google.gerrit.server.restapi.account.GetEmails;
import com.google.gerrit.server.restapi.account.GetSshKeys;
@@ -122,10 +125,18 @@
@Option(name = "--generate-http-password", usage = "generate a new HTTP password for the account")
private boolean generateHttpPassword;
+ @Option(
+ name = "--delete-external-id",
+ metaVar = "EXTERNALID",
+ usage = "external id to delete from the account")
+ private List<String> externalIdsToDelete = new ArrayList<>();
+
@Inject private IdentifiedUser.GenericFactory genericUserFactory;
@Inject private CreateEmail createEmail;
+ @Inject private DeleteExternalIds deleteExternalIds;
+
@Inject private GetEmails getEmails;
@Inject private DeleteEmail deleteEmail;
@@ -150,6 +161,8 @@
@Inject private Provider<CurrentUser> userProvider;
+ @Inject private ExternalIds externalIds;
+
private AccountResource rsrc;
@Override
@@ -210,6 +223,9 @@
"--preferred-email and --delete-email options are mutually "
+ "exclusive for the same email address.");
}
+ if (externalIdsToDelete.contains("ALL")) {
+ externalIdsToDelete = Collections.singletonList("ALL");
+ }
}
private void setAccount() throws Failure {
@@ -265,6 +281,10 @@
if (!deleteSshKeys.isEmpty()) {
deleteSshKeys(deleteSshKeys);
}
+
+ for (String externalId : externalIdsToDelete) {
+ deleteExternalId(externalId);
+ }
} catch (RestApiException e) {
throw die(e.getMessage());
} catch (Exception e) {
@@ -355,4 +375,21 @@
}
return sshKeys;
}
+
+ private void deleteExternalId(String externalId)
+ throws IOException, RestApiException, ConfigInvalidException, PermissionBackendException {
+ List<String> ids;
+ if (externalId.equals("ALL")) {
+ ids =
+ externalIds.byAccount(rsrc.getUser().getAccountId()).stream()
+ .map(e -> e.key().get())
+ .collect(toList());
+ if (ids.isEmpty()) {
+ throw new ResourceNotFoundException("Account has no external Ids");
+ }
+ } else {
+ ids = Collections.singletonList(externalId);
+ }
+ deleteExternalIds.apply(rsrc, ids);
+ }
}
diff --git a/java/com/google/gerrit/testing/GerritJUnit.java b/java/com/google/gerrit/testing/GerritJUnit.java
index 0771c39..e80afa9 100644
--- a/java/com/google/gerrit/testing/GerritJUnit.java
+++ b/java/com/google/gerrit/testing/GerritJUnit.java
@@ -26,11 +26,11 @@
* <p>This construction is recommended by the Truth team for use in conjunction with asserting
* over a {@code ThrowableSubject} on the return type:
*
- * <pre>
- * MyException e = assertThrows(MyException.class, () -> doSomething(foo));
- * assertThat(e).isInstanceOf(MySubException.class);
- * assertThat(e).hasMessageThat().contains("sub-exception occurred");
- * </pre>
+ * <pre>{@code
+ * MyException e = assertThrows(MyException.class, () -> doSomething(foo));
+ * assertThat(e).isInstanceOf(MySubException.class);
+ * assertThat(e).hasMessageThat().contains("sub-exception occurred");
+ * }</pre>
*
* @param throwableClass expected exception type.
* @param runnable runnable containing arbitrary code.
diff --git a/java/com/google/gerrit/testing/GerritServerTests.java b/java/com/google/gerrit/testing/GerritServerTests.java
index 363a07d..752c13d 100644
--- a/java/com/google/gerrit/testing/GerritServerTests.java
+++ b/java/com/google/gerrit/testing/GerritServerTests.java
@@ -26,7 +26,6 @@
@RunWith(ConfigSuite.class)
public class GerritServerTests {
@ConfigSuite.Parameter public Config config;
- @ConfigSuite.Name private String configName;
@Rule
public TestRule testRunner =
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index 12da2c1..3949de0 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -44,6 +44,7 @@
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.FileInfoJsonModule;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.config.AllUsersName;
@@ -54,6 +55,7 @@
import com.google.gerrit.server.config.CanonicalWebUrlModule;
import com.google.gerrit.server.config.CanonicalWebUrlProvider;
import com.google.gerrit.server.config.DefaultUrlFormatter;
+import com.google.gerrit.server.config.FileBasedAllProjectsConfigProvider;
import com.google.gerrit.server.config.FileBasedGlobalPluginConfigProvider;
import com.google.gerrit.server.config.GerritGlobalModule;
import com.google.gerrit.server.config.GerritInstanceIdModule;
@@ -196,6 +198,7 @@
bind(Path.class).annotatedWith(SitePath.class).toInstance(Paths.get("."));
bind(Config.class).annotatedWith(GerritServerConfig.class).toInstance(cfg);
bind(GerritOptions.class).toInstance(new GerritOptions(false, false));
+ bind(AllProjectsConfigProvider.class).to(FileBasedAllProjectsConfigProvider.class);
bind(GlobalPluginConfigProvider.class).to(FileBasedGlobalPluginConfigProvider.class);
bind(GitRepositoryManager.class).to(InMemoryRepositoryManager.class);
diff --git a/java/com/google/gerrit/testing/InMemoryRepositoryManager.java b/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
index 09ae115..362e23c 100644
--- a/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
+++ b/java/com/google/gerrit/testing/InMemoryRepositoryManager.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.inject.Inject;
@@ -79,6 +80,16 @@
}
@Override
+ public synchronized Status getRepositoryStatus(NameKey name) {
+ try {
+ get(name);
+ return Status.ACTIVE;
+ } catch (RepositoryNotFoundException e) {
+ return Status.NON_EXISTENT;
+ }
+ }
+
+ @Override
public synchronized Repo openRepository(Project.NameKey name) throws RepositoryNotFoundException {
return get(name);
}
diff --git a/java/com/google/gerrit/testing/InMemoryTestEnvironment.java b/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
index 44d5cea..77df46c 100644
--- a/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
+++ b/java/com/google/gerrit/testing/InMemoryTestEnvironment.java
@@ -46,6 +46,7 @@
@Inject private IdentifiedUser.GenericFactory userFactory;
@Inject private SchemaCreator schemaCreator;
@Inject private ThreadLocalRequestContext requestContext;
+ @Inject private AuthRequest.Factory authRequestFactory;
private LifecycleManager lifecycle;
@@ -99,7 +100,8 @@
schemaCreator.create();
// The first user is added to the "Administrators" group. See AccountManager#create().
- setApiUser(accountManager.authenticate(AuthRequest.forUser("admin")).getAccountId());
+ setApiUser(
+ accountManager.authenticate(authRequestFactory.createForUser("admin")).getAccountId());
// Inject target members after setting API user, so it can @Inject request-scoped objects if it
// wants.
diff --git a/java/com/google/gerrit/util/http/RequestUtil.java b/java/com/google/gerrit/util/http/RequestUtil.java
index 92d9967..f64ce5a 100644
--- a/java/com/google/gerrit/util/http/RequestUtil.java
+++ b/java/com/google/gerrit/util/http/RequestUtil.java
@@ -31,8 +31,8 @@
}
/**
- * @return the same value as {@link HttpServletRequest#getPathInfo()}, but without decoding
- * URL-encoded characters.
+ * Returns the same value as {@link HttpServletRequest#getPathInfo()}, but without decoding
+ * URL-encoded characters.
*/
public static String getEncodedPathInfo(HttpServletRequest req) {
// CS IGNORE LineLength FOR NEXT 3 LINES. REASON: URL.
diff --git a/java/gerrit/BUILD b/java/gerrit/BUILD
index db831b7..fea2696 100644
--- a/java/gerrit/BUILD
+++ b/java/gerrit/BUILD
@@ -5,6 +5,7 @@
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
deps = [
+ "//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/entities",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/server",
diff --git a/java/gerrit/PRED_commit_edits_2.java b/java/gerrit/PRED_commit_edits_2.java
index 12e7086..6083010 100644
--- a/java/gerrit/PRED_commit_edits_2.java
+++ b/java/gerrit/PRED_commit_edits_2.java
@@ -14,10 +14,13 @@
package gerrit;
+import com.google.common.collect.Iterables;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.FilePathAdapter;
import com.google.gerrit.server.patch.Text;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
+import com.google.gerrit.server.patch.filediff.TaggedEdit;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.IllegalTypeException;
import com.googlecode.prolog_cafe.exceptions.JavaException;
@@ -31,7 +34,9 @@
import com.googlecode.prolog_cafe.lang.VariableTerm;
import java.io.IOException;
import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -40,7 +45,6 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
@@ -69,27 +73,26 @@
Pattern fileRegex = getRegexParameter(a1);
Pattern editRegex = getRegexParameter(a2);
- PatchList pl = StoredValues.PATCH_LIST.get(engine);
+ Map<String, FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine);
+ FileDiffOutput firstDiff = Iterables.getFirst(modifiedFiles.values(), /* defaultValue= */ null);
+ if (firstDiff == null) {
+ // No available diffs. We cannot identify old and new commit IDs.
+ engine.fail();
+ }
Repository repo = StoredValues.REPOSITORY.get(engine);
try (ObjectReader reader = repo.newObjectReader();
RevWalk rw = new RevWalk(reader)) {
- final RevTree aTree;
- final RevTree bTree;
- final RevCommit bCommit = rw.parseCommit(pl.getNewId());
+ final RevTree aTree =
+ firstDiff.oldCommitId().equals(ObjectId.zeroId())
+ ? null
+ : rw.parseTree(firstDiff.oldCommitId());
+ final RevTree bTree = rw.parseCommit(firstDiff.newCommitId()).getTree();
- if (pl.getOldId() != null) {
- aTree = rw.parseTree(pl.getOldId());
- } else {
- // Octopus merge with unknown automatic merge result, since the
- // web UI returns no files to match against, just fail.
- return engine.fail();
- }
- bTree = bCommit.getTree();
-
- for (PatchListEntry entry : pl.getPatches()) {
- String newName = entry.getNewName();
- String oldName = entry.getOldName();
+ for (FileDiffOutput entry : modifiedFiles.values()) {
+ String newName =
+ FilePathAdapter.getNewPath(entry.oldPath(), entry.newPath(), entry.changeType());
+ String oldName = FilePathAdapter.getOldPath(entry.oldPath(), entry.changeType());
if (Patch.isMagic(newName)) {
continue;
@@ -97,7 +100,8 @@
if (fileRegex.matcher(newName).find()
|| (oldName != null && fileRegex.matcher(oldName).find())) {
- List<Edit> edits = entry.getEdits();
+ List<Edit> edits =
+ entry.edits().stream().map(TaggedEdit::jgitEdit).collect(Collectors.toList());
if (edits.isEmpty()) {
continue;
}
@@ -141,10 +145,10 @@
return Pattern.compile(term.name(), Pattern.MULTILINE);
}
- private Text load(ObjectId tree, String path, ObjectReader reader)
+ private Text load(@Nullable ObjectId tree, String path, ObjectReader reader)
throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException,
IOException {
- if (path == null) {
+ if (tree == null || path == null) {
return Text.EMPTY;
}
final TreeWalk tw = TreeWalk.forPath(reader, path, tree);
diff --git a/java/gerrit/PRED_commit_stats_3.java b/java/gerrit/PRED_commit_stats_3.java
index 286bc2c..82fad3d 100644
--- a/java/gerrit/PRED_commit_stats_3.java
+++ b/java/gerrit/PRED_commit_stats_3.java
@@ -15,8 +15,7 @@
package gerrit;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.IntegerTerm;
@@ -24,7 +23,8 @@
import com.googlecode.prolog_cafe.lang.Predicate;
import com.googlecode.prolog_cafe.lang.Prolog;
import com.googlecode.prolog_cafe.lang.Term;
-import java.util.List;
+import java.util.Collection;
+import java.util.Map;
/**
* Exports basic commit statistics.
@@ -49,25 +49,30 @@
Term a2 = arg2.dereference();
Term a3 = arg3.dereference();
- PatchList pl = StoredValues.PATCH_LIST.get(engine);
+ Map<String, FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine);
// Account for magic files
if (!a1.unify(
- new IntegerTerm(pl.getPatches().size() - countMagicFiles(pl.getPatches())), engine.trail)) {
+ new IntegerTerm(modifiedFiles.size() - countMagicFiles(modifiedFiles.values())),
+ engine.trail)) {
return engine.fail();
}
- if (!a2.unify(new IntegerTerm(pl.getInsertions()), engine.trail)) {
+ Integer insertions =
+ modifiedFiles.values().stream().map(FileDiffOutput::insertions).reduce(0, Integer::sum);
+ Integer deletions =
+ modifiedFiles.values().stream().map(FileDiffOutput::deletions).reduce(0, Integer::sum);
+ if (!a2.unify(new IntegerTerm(insertions), engine.trail)) {
return engine.fail();
}
- if (!a3.unify(new IntegerTerm(pl.getDeletions()), engine.trail)) {
+ if (!a3.unify(new IntegerTerm(deletions), engine.trail)) {
return engine.fail();
}
return cont;
}
- private int countMagicFiles(List<PatchListEntry> entries) {
+ private int countMagicFiles(Collection<FileDiffOutput> entries) {
int count = 0;
- for (PatchListEntry e : entries) {
- if (Patch.isMagic(e.getNewName())) {
+ for (FileDiffOutput e : entries) {
+ if (e.newPath().isPresent() && Patch.isMagic(e.newPath().get())) {
count++;
}
}
diff --git a/java/gerrit/PRED_files_1.java b/java/gerrit/PRED_files_1.java
index ac45449..dbf96da 100644
--- a/java/gerrit/PRED_files_1.java
+++ b/java/gerrit/PRED_files_1.java
@@ -15,7 +15,8 @@
package gerrit;
import com.google.gerrit.entities.Patch;
-import com.google.gerrit.server.patch.PatchListEntry;
+import com.google.gerrit.server.patch.FilePathAdapter;
+import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.gerrit.server.rules.StoredValues;
import com.googlecode.prolog_cafe.exceptions.PrologException;
import com.googlecode.prolog_cafe.lang.ListTerm;
@@ -26,8 +27,8 @@
import com.googlecode.prolog_cafe.lang.SymbolTerm;
import com.googlecode.prolog_cafe.lang.Term;
import java.io.IOException;
+import java.util.Collection;
import java.util.HashSet;
-import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.FileMode;
@@ -54,17 +55,20 @@
try (RevWalk revWalk = new RevWalk(StoredValues.REPOSITORY.get(engine))) {
RevCommit commit = revWalk.parseCommit(StoredValues.getPatchSet(engine).commitId());
- List<PatchListEntry> patches = StoredValues.PATCH_LIST.get(engine).getPatches();
+ Collection<FileDiffOutput> modifiedFiles = StoredValues.DIFF_LIST.get(engine).values();
Set<String> submodules =
- getAllSubmodulePaths(StoredValues.REPOSITORY.get(engine), commit, patches);
- for (PatchListEntry entry : patches) {
- if (Patch.isMagic(entry.getNewName())) {
+ getAllSubmodulePaths(StoredValues.REPOSITORY.get(engine), commit, modifiedFiles);
+ for (FileDiffOutput fileDiff : modifiedFiles) {
+ if (fileDiff.newPath().isPresent() && Patch.isMagic(fileDiff.newPath().get())) {
continue;
}
- SymbolTerm fileNameTerm = SymbolTerm.create(entry.getNewName());
- SymbolTerm changeType = SymbolTerm.create(entry.getChangeType().getCode());
+ String newPath =
+ FilePathAdapter.getNewPath(
+ fileDiff.oldPath(), fileDiff.newPath(), fileDiff.changeType());
+ SymbolTerm fileNameTerm = SymbolTerm.create(newPath);
+ SymbolTerm changeType = SymbolTerm.create(fileDiff.changeType().getCode());
SymbolTerm fileType;
- if (submodules.contains(entry.getNewName())) {
+ if (submodules.contains(newPath)) {
fileType = SymbolTerm.create("SUBMODULE");
} else {
fileType = SymbolTerm.create("REGULAR");
@@ -83,14 +87,14 @@
/** Returns the paths for all {@code GITLINK} files. */
private static Set<String> getAllSubmodulePaths(
- Repository repository, RevCommit commit, List<PatchListEntry> patches)
+ Repository repository, RevCommit commit, Collection<FileDiffOutput> modifiedFiles)
throws PrologException, IOException {
Set<String> submodules = new HashSet<>();
try (TreeWalk treeWalk = new TreeWalk(repository)) {
treeWalk.addTree(commit.getTree());
Set<String> allPaths =
- patches.stream()
- .map(PatchListEntry::getNewName)
+ modifiedFiles.stream()
+ .map(f -> FilePathAdapter.getNewPath(f.oldPath(), f.newPath(), f.changeType()))
.filter(f -> !Patch.isMagic(f))
.collect(Collectors.toSet());
treeWalk.setFilter(PathFilterGroup.createFromStrings(allPaths));
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
index 8c7d892..1da2176c 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountIT.java
@@ -32,7 +32,6 @@
import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithSecondUserId;
import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithoutExpiration;
import static com.google.gerrit.server.StarredChangesUtil.DEFAULT_LABEL;
-import static com.google.gerrit.server.StarredChangesUtil.IGNORE_LABEL;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
import static com.google.gerrit.server.group.SystemGroupBackend.ANONYMOUS_USERS;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
@@ -98,7 +97,6 @@
import com.google.gerrit.extensions.api.changes.DraftInput;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewerInput;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInput;
@@ -133,6 +131,8 @@
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
@@ -231,6 +231,8 @@
@Inject private VersionedAuthorizedKeys.Accessor authorizedKeys;
@Inject private ExtensionRegistry extensionRegistry;
@Inject private PluginSetContext<ExceptionHook> exceptionHooks;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@Inject protected Emails emails;
@@ -374,8 +376,8 @@
accountIndexedCounter.assertReindexOf(accountId, 1);
assertThat(externalIds.byAccount(accountId))
.containsExactly(
- ExternalId.createUsername(input.username, accountId, null),
- ExternalId.createEmail(accountId, input.email));
+ externalIdFactory.createUsername(input.username, accountId, null),
+ externalIdFactory.createEmail(accountId, input.email));
}
}
@@ -428,7 +430,7 @@
public void createAtomically() throws Exception {
Account.Id accountId = Account.id(seq.nextAccountId());
String fullName = "Foo";
- ExternalId extId = ExternalId.createEmail(accountId, "foo@example.com");
+ ExternalId extId = externalIdFactory.createEmail(accountId, "foo@example.com");
AccountState accountState =
accountsUpdateProvider
.get()
@@ -792,126 +794,7 @@
}
@Test
- public void starUnstarChangeWithLabels() throws Exception {
- AccountIndexedCounter accountIndexedCounter = new AccountIndexedCounter();
- RefUpdateCounter refUpdateCounter = new RefUpdateCounter();
- try (Registration registration =
- extensionRegistry.newRegistration().add(accountIndexedCounter).add(refUpdateCounter)) {
- PushOneCommit.Result r = createChange();
- String triplet = project.get() + "~master~" + r.getChangeId();
- refUpdateCounter.clear();
-
- assertThat(gApi.accounts().self().getStars(triplet)).isEmpty();
- assertThat(gApi.accounts().self().getStarredChanges()).isEmpty();
-
- gApi.accounts()
- .self()
- .setStars(triplet, new StarsInput(ImmutableSet.of(DEFAULT_LABEL, "red", "blue")));
- ChangeInfo change = info(triplet);
- assertThat(change.starred).isTrue();
- assertThat(change.stars).containsExactly("blue", "red", DEFAULT_LABEL).inOrder();
- assertThat(gApi.accounts().self().getStars(triplet))
- .containsExactly("blue", "red", DEFAULT_LABEL)
- .inOrder();
- List<ChangeInfo> starredChanges = gApi.accounts().self().getStarredChanges();
- assertThat(starredChanges).hasSize(1);
- ChangeInfo starredChange = starredChanges.get(0);
- assertThat(starredChange._number).isEqualTo(r.getChange().getId().get());
- assertThat(starredChange.starred).isTrue();
- assertThat(starredChange.stars).containsExactly("blue", "red", DEFAULT_LABEL).inOrder();
- refUpdateCounter.assertRefUpdateFor(
- RefUpdateCounter.projectRef(
- allUsers, RefNames.refsStarredChanges(Change.id(change._number), admin.id())));
-
- gApi.accounts()
- .self()
- .setStars(
- triplet,
- new StarsInput(ImmutableSet.of("yellow"), ImmutableSet.of(DEFAULT_LABEL, "blue")));
- change = info(triplet);
- assertThat(change.starred).isNull();
- assertThat(change.stars).containsExactly("red", "yellow").inOrder();
- assertThat(gApi.accounts().self().getStars(triplet))
- .containsExactly("red", "yellow")
- .inOrder();
- starredChanges = gApi.accounts().self().getStarredChanges();
- assertThat(starredChanges).hasSize(1);
- starredChange = starredChanges.get(0);
- assertThat(starredChange._number).isEqualTo(r.getChange().getId().get());
- assertThat(starredChange.starred).isNull();
- assertThat(starredChange.stars).containsExactly("red", "yellow").inOrder();
- refUpdateCounter.assertRefUpdateFor(
- RefUpdateCounter.projectRef(
- allUsers, RefNames.refsStarredChanges(Change.id(change._number), admin.id())));
-
- accountIndexedCounter.assertNoReindex();
-
- requestScopeOperations.setApiUser(user.id());
- AuthException thrown =
- assertThrows(
- AuthException.class,
- () -> gApi.accounts().id(Integer.toString((admin.id().get()))).getStars(triplet));
- assertThat(thrown).hasMessageThat().contains("not allowed to get stars of another account");
- }
- }
-
- @Test
- public void starWithInvalidLabels() throws Exception {
- PushOneCommit.Result r = createChange();
- String triplet = project.get() + "~master~" + r.getChangeId();
- BadRequestException thrown =
- assertThrows(
- BadRequestException.class,
- () ->
- gApi.accounts()
- .self()
- .setStars(
- triplet,
- new StarsInput(
- ImmutableSet.of(
- DEFAULT_LABEL, "invalid label", "blue", "another invalid label"))));
- assertThat(thrown)
- .hasMessageThat()
- .contains("invalid labels: another invalid label, invalid label");
- }
-
- @Test
- public void deleteStarLabelsFromChangeWithoutStarLabels() throws Exception {
- PushOneCommit.Result r = createChange();
- String triplet = project.get() + "~master~" + r.getChangeId();
- assertThat(gApi.accounts().self().getStars(triplet)).isEmpty();
-
- gApi.accounts().self().setStars(triplet, new StarsInput());
-
- assertThat(gApi.accounts().self().getStars(triplet)).isEmpty();
- }
-
- @Test
- public void starWithDefaultAndIgnoreLabel() throws Exception {
- PushOneCommit.Result r = createChange();
- String triplet = project.get() + "~master~" + r.getChangeId();
- BadRequestException thrown =
- assertThrows(
- BadRequestException.class,
- () ->
- gApi.accounts()
- .self()
- .setStars(
- triplet,
- new StarsInput(ImmutableSet.of(DEFAULT_LABEL, "blue", IGNORE_LABEL))));
- assertThat(thrown)
- .hasMessageThat()
- .contains(
- "The labels "
- + DEFAULT_LABEL
- + " and "
- + IGNORE_LABEL
- + " are mutually exclusive."
- + " Only one of them can be set.");
- }
-
- @Test
- public void ignoreChangeBySetStars() throws Exception {
+ public void ignoreChange() throws Exception {
AccountIndexedCounter accountIndexedCounter = new AccountIndexedCounter();
try (Registration registration =
extensionRegistry.newRegistration().add(accountIndexedCounter)) {
@@ -929,9 +812,7 @@
gApi.changes().id(r.getChangeId()).addReviewer(in);
requestScopeOperations.setApiUser(user.id());
- gApi.accounts()
- .self()
- .setStars(r.getChangeId(), new StarsInput(ImmutableSet.of(IGNORE_LABEL)));
+ gApi.changes().id(r.getChangeId()).ignore(true);
sender.clear();
requestScopeOperations.setApiUser(admin.id());
@@ -951,9 +832,7 @@
PushOneCommit.Result r = createChange();
requestScopeOperations.setApiUser(user.id());
- gApi.accounts()
- .self()
- .setStars(r.getChangeId(), new StarsInput(ImmutableSet.of(IGNORE_LABEL)));
+ gApi.changes().id(r.getChangeId()).ignore(true);
sender.clear();
requestScopeOperations.setApiUser(admin.id());
@@ -962,11 +841,7 @@
in.reviewer = user.email();
gApi.changes().id(r.getChangeId()).addReviewer(in);
List<Message> messages = sender.getMessages();
- assertThat(messages).hasSize(1);
- Message message = messages.get(0);
- assertThat(message.rcpt()).containsExactly(user.getNameEmail());
- assertMailReplyTo(message, admin.email());
- accountIndexedCounter.assertNoReindex();
+ assertThat(messages).hasSize(0);
}
}
@@ -1407,11 +1282,11 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(extId1), admin.id(), email))
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId1), admin.id(), email))
.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(extId2), admin.id(), email)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId2), admin.id(), email)));
accountIndexedCounter.assertReindexOf(admin);
assertThat(
gApi.accounts().self().getExternalIds().stream()
@@ -1447,8 +1322,8 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(ldapExternalId), admin.id(), ldapEmail)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(ldapExternalId), admin.id(), ldapEmail)));
assertThat(
gApi.accounts().self().getExternalIds().stream().map(e -> e.identity).collect(toSet()))
.contains(ldapExternalId);
@@ -1482,11 +1357,13 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(nonLdapExternalId), admin.id(), nonLdapEMail))
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(nonLdapExternalId),
+ admin.id(),
+ nonLdapEMail))
.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse(ldapExternalId), admin.id(), ldapEmail)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(ldapExternalId), admin.id(), ldapEmail)));
assertThat(
gApi.accounts().self().getExternalIds().stream().map(e -> e.identity).collect(toSet()))
.containsAtLeast(ldapExternalId, nonLdapExternalId);
@@ -1549,8 +1426,8 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
- ExternalId.Key.parse("foo:bar"), admin.id(), email)));
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), email)));
assertEmail(emails.getAccountFor(email), admin);
// wrong case doesn't match
@@ -1866,7 +1743,7 @@
.update(
"Add External ID",
user.id(),
- u -> u.addExternalId(ExternalId.create("foo", "myId", user.id())));
+ u -> u.addExternalId(externalIdFactory.create("foo", "myId", user.id())));
accountIndexedCounter.assertReindexOf(user);
TestKey key = validKeyWithSecondUserId();
@@ -2169,7 +2046,7 @@
.update(
"Delete External ID",
account.id(),
- u -> u.deleteExternalId(ExternalId.createEmail(account.id(), email)));
+ u -> u.deleteExternalId(externalIdFactory.createEmail(account.id(), email)));
expectedProblems.add(
new ConsistencyProblemInfo(
ConsistencyProblemInfo.Status.ERROR,
@@ -2504,7 +2381,7 @@
.update();
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId extIdA1 = ExternalId.create("foo", "A-1", accountId);
+ ExternalId extIdA1 = externalIdFactory.create("foo", "A-1", accountId);
accountsUpdateProvider
.get()
.insert("Create Test Account", accountId, u -> u.addExternalId(extIdA1));
@@ -2512,7 +2389,7 @@
AtomicInteger bgCounterA1 = new AtomicInteger(0);
AtomicInteger bgCounterA2 = new AtomicInteger(0);
PersonIdent ident = serverIdent.get();
- ExternalId extIdA2 = ExternalId.create("foo", "A-2", accountId);
+ ExternalId extIdA2 = externalIdFactory.create("foo", "A-2", accountId);
AccountsUpdate update =
new AccountsUpdate(
repoManager,
@@ -2553,8 +2430,8 @@
.collect(toSet()))
.containsExactly(extIdA1.key().get());
- ExternalId extIdB1 = ExternalId.create("foo", "B-1", accountId);
- ExternalId extIdB2 = ExternalId.create("foo", "B-2", accountId);
+ ExternalId extIdB1 = externalIdFactory.create("foo", "B-1", accountId);
+ ExternalId extIdB2 = externalIdFactory.create("foo", "B-2", accountId);
Optional<AccountState> updatedAccount =
update.update(
"Update External ID",
@@ -2617,23 +2494,24 @@
// Manually inserting/updating/deleting an external ID of the user makes the index document
// stale.
try (Repository repo = repoManager.openRepository(allUsers)) {
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
- ExternalId.Key key = ExternalId.Key.create("foo", "foo");
- extIdNotes.insert(ExternalId.create(key, accountId));
+ ExternalId.Key key = externalIdKeyFactory.create("foo", "foo");
+ extIdNotes.insert(externalIdFactory.create(key, accountId));
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
}
assertStaleAccountAndReindex(accountId);
- extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
- extIdNotes.upsert(ExternalId.createWithEmail(key, accountId, "foo@example.com"));
+ extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
+ extIdNotes.upsert(externalIdFactory.createWithEmail(key, accountId, "foo@example.com"));
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
}
assertStaleAccountAndReindex(accountId);
- extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
extIdNotes.delete(accountId, key);
try (MetaDataUpdate update = metaDataUpdateFactory.create(allUsers)) {
extIdNotes.commit(update);
@@ -2894,9 +2772,11 @@
String extId1String = "foo:bar";
String extId2String = "foo:baz";
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse(extId1String), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId1String), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse(extId2String), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(extId2String), user.id(), "2@foo.com");
ObjectId revBefore;
try (Repository repo = repoManager.openRepository(allUsers)) {
@@ -2936,9 +2816,11 @@
@Test
public void externalIdBatchUpdates_fail_sameAccount() {
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:baz"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:baz"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -2957,9 +2839,11 @@
@Test
public void externalIdBatchUpdates_fail_duplicateKey() {
ExternalId extIdAdmin =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extIdUser =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -2977,9 +2861,11 @@
@Test
public void externalIdBatchUpdates_commitMsg_multipleAccounts() throws Exception {
ExternalId extId1 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
ExternalId extId2 =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:baz"), user.id(), "2@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:baz"), user.id(), "2@foo.com");
AccountsUpdate.UpdateArguments ua1 =
new AccountsUpdate.UpdateArguments(
@@ -3001,7 +2887,8 @@
@Test
public void externalIdBatchUpdates_commitMsg_singleAccount() throws Exception {
ExternalId extId =
- ExternalId.createWithEmail(ExternalId.Key.parse("foo:bar"), admin.id(), "1@foo.com");
+ externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse("foo:bar"), admin.id(), "1@foo.com");
accountsUpdateProvider.get().update("foobar", admin.id(), (a, u) -> u.addExternalId(extId));
@@ -3158,7 +3045,7 @@
account.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(name("test"), email, account.id(), email)));
+ externalIdFactory.createWithEmail(name("test"), email, account.id(), email)));
accountIndexedCounter.assertReindexOf(account);
requestScopeOperations.setApiUser(account.id());
}
diff --git a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
index b41a2f3..7e23f0e 100644
--- a/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/accounts/AccountManagerIT.java
@@ -37,6 +37,8 @@
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.account.SetInactiveFlag;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -62,14 +64,17 @@
@Inject private SshKeyCache sshKeyCache;
@Inject private GroupsUpdate.Factory groupsUpdateFactory;
@Inject private SetInactiveFlag setInactiveFlag;
+ @Inject private AuthRequest.Factory authRequestFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Test
public void authenticateNewAccountWithEmail() throws Exception {
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertNoSuchExternalIds(mailtoExtIdKey);
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, mailtoExtIdKey);
assertExternalId(mailtoExtIdKey, email);
@@ -78,11 +83,12 @@
@Test
public void authenticateNewAccountWithUsername() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
assertNoSuchExternalIds(gerritExtIdKey, usernameExtIdKey);
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, gerritExtIdKey);
assertExternalIdsWithoutEmail(gerritExtIdKey, usernameExtIdKey);
@@ -91,11 +97,12 @@
@Test
public void authenticateNewAccountWithUsernameAndEmail() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
assertNoSuchExternalIds(gerritExtIdKey, usernameExtIdKey);
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String email = "foo@example.com";
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -107,12 +114,14 @@
@Test
public void authenticateNewAccountWithExternalUser() throws Exception {
String username = "foo";
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(externalExtIdKey, usernameExtIdKey, gerritExtIdKey);
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForNewAccount(authResult, externalExtIdKey);
assertExternalIdsWithoutEmail(externalExtIdKey, usernameExtIdKey);
@@ -122,12 +131,14 @@
@Test
public void authenticateNewAccountWithExternalUserAndEmail() throws Exception {
String username = "foo";
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
- ExternalId.Key usernameExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_USERNAME, username);
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key usernameExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_USERNAME, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(externalExtIdKey, usernameExtIdKey, gerritExtIdKey);
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
String email = "foo@example.com";
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -141,13 +152,13 @@
public void authenticateWithEmail() throws Exception {
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(mailtoExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(mailtoExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, mailtoExtIdKey);
}
@@ -156,13 +167,13 @@
public void authenticateWithUsername() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, gerritExtIdKey);
}
@@ -171,13 +182,14 @@
public void authenticateWithExternalUser() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
AuthResult authResult = accountManager.authenticate(who);
assertAuthResultForExistingAccount(authResult, accountId, externalExtIdKey);
}
@@ -187,15 +199,16 @@
String username = "foo";
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String newEmail = "bar@example.com";
who.setEmailAddress(newEmail);
AuthResult authResult = accountManager.authenticate(who);
@@ -233,23 +246,26 @@
projectCache,
externalIds,
groupsUpdateFactory,
- setInactiveFlag));
+ setInactiveFlag,
+ externalIdFactory,
+ externalIdKeyFactory));
}
private void authenticateWithUsernameAndUpdateDisplayName(AccountManager am) throws Exception {
String username = "foo";
String email = "foo@example.com";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setFullName("Initial Name")
.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
String newName = "Updated Name";
who.setDisplayName(newName);
AuthResult authResult = am.authenticate(who);
@@ -263,12 +279,12 @@
@Test
public void cannotAuthenticateWithOrphanedExtId() throws Exception {
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
assertNoSuchExternalIds(gerritExtIdKey);
// Create orphaned SCHEME_GERRIT external ID.
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId gerritExtId = ExternalId.create(gerritExtIdKey, accountId);
+ ExternalId gerritExtId = externalIdFactory.create(gerritExtIdKey, accountId);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = extIdNotesFactory.load(allUsersRepo);
@@ -276,7 +292,7 @@
extIdNotes.commit(md);
}
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown).hasMessageThat().contains("Authentication error, account not found");
@@ -286,13 +302,13 @@
public void cannotAuthenticateWithInactiveAccount() throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown).hasMessageThat().contains("Authentication error, account inactive");
@@ -303,13 +319,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(true);
who.setAuthProvidesAccountActiveStatus(true);
AccountException thrown =
@@ -323,13 +339,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.setActive(false).addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.setActive(false).addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(true);
who.setAuthProvidesAccountActiveStatus(true);
AuthResult authResult = accountManager.authenticate(who);
@@ -344,13 +360,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(false);
who.setAuthProvidesAccountActiveStatus(true);
AuthResult authResult = accountManager.authenticate(who);
@@ -366,13 +382,13 @@
throws Exception {
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setActive(false);
who.setAuthProvidesAccountActiveStatus(true);
AccountException thrown =
@@ -391,15 +407,17 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Try to authenticate with this email to create a new account with a SCHEME_MAILTO external ID.
// Expect that this fails because the email is already assigned to the other account.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
assertThat(thrown)
@@ -414,15 +432,17 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Try to authenticate with a new username and claim the same email.
// Expect that this fails because the email is already assigned to the other account.
- AuthRequest who = AuthRequest.forUser("bar");
+ AuthRequest who = authRequestFactory.createForUser("bar");
who.setEmailAddress(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
@@ -439,25 +459,29 @@
// Create an account with a SCHEME_GERRIT external ID and an email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.setPreferredEmail(email)
- .addExternalId(ExternalId.createWithEmail(gerritExtIdKey, accountId, email)));
+ .addExternalId(
+ externalIdFactory.createWithEmail(gerritExtIdKey, accountId, email)));
// Create another account with an SCHEME_EXTERNAL external ID that occupies the new email.
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, "bar");
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, "bar");
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId2, newEmail)));
+ u ->
+ u.addExternalId(
+ externalIdFactory.createWithEmail(externalExtIdKey, accountId2, newEmail)));
// Try to authenticate and update the email for the first account.
// Expect that this fails because the new email is already assigned to the other account.
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setEmailAddress(newEmail);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.authenticate(who));
@@ -482,21 +506,21 @@
// Create an account with a SCHEME_GERRIT external ID
String username = "foo";
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
Account.Id accountId = Account.id(seq.nextAccountId());
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
// Add the additional mail external ID with SCHEME_EMAIL
- accountManager.link(accountId, AuthRequest.forEmail(email));
+ accountManager.link(accountId, authRequestFactory.createForEmail(email));
// Try to authenticate and update the email for the account.
// Expect that this to succeed because even if the email already exist
// it is associated to the same account-id and thus is not really
// a duplicate but simply a promotion of external id to preferred email.
- AuthRequest who = AuthRequest.forUser(username);
+ AuthRequest who = authRequestFactory.createForUser(username);
who.setEmailAddress(email);
AuthResult authResult = accountManager.authenticate(who);
@@ -519,20 +543,20 @@
// Create an account with a SCHEME_GERRIT external ID and no email
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username);
+ ExternalId.Key gerritExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId)));
// Check that email is not used yet.
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertNoSuchExternalIds(mailtoExtIdKey);
// Link the email to the account.
// Expect that a MAILTO external ID is created.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult authResult = accountManager.link(accountId, who);
assertAuthResultForExistingAccount(authResult, accountId, mailtoExtIdKey);
assertExternalId(mailtoExtIdKey, accountId, email);
@@ -543,17 +567,18 @@
// Create an account with a SCHEME_GERRIT external ID and no email
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
u ->
u.addExternalId(
- ExternalId.createWithEmail(externalExtIdKey, accountId, "old@example.com")));
+ externalIdFactory.createWithEmail(externalExtIdKey, accountId, "old@example.com")));
// Link the email to the existing SCHEME_EXTERNAL external ID, but with a new email.
// Expect that the email of the existing external ID is updated.
- AuthRequest who = AuthRequest.forExternalUser(username);
+ AuthRequest who = authRequestFactory.createForExternalUser(username);
String newEmail = "new@example.com";
who.setEmailAddress(newEmail);
AuthResult authResult = accountManager.link(accountId, who);
@@ -566,24 +591,26 @@
// Create an account with a SCHEME_EXTERNAL external ID
String username1 = "foo";
Account.Id accountId1 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey1 = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username1);
+ ExternalId.Key externalExtIdKey1 =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username1);
accountsUpdate.insert(
"Create Test Account",
accountId1,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey1, accountId1)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey1, accountId1)));
// Create another account with a SCHEME_EXTERNAL external ID
String username2 = "bar";
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey2 = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username2);
+ ExternalId.Key externalExtIdKey2 =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username2);
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.create(externalExtIdKey2, accountId2)));
+ u -> u.addExternalId(externalIdFactory.create(externalExtIdKey2, accountId2)));
// Try to link external ID of the first account to the second account.
// Expect that this fails because the external ID is already assigned to the first account.
- AuthRequest who = AuthRequest.forExternalUser(username1);
+ AuthRequest who = authRequestFactory.createForExternalUser(username1);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.link(accountId2, who));
assertThat(thrown)
@@ -598,24 +625,27 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
// Create another account with a SCHEME_GERRIT external ID and no email
String username2 = "foo";
Account.Id accountId2 = Account.id(seq.nextAccountId());
- ExternalId.Key gerritExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_GERRIT, username2);
+ ExternalId.Key gerritExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_GERRIT, username2);
accountsUpdate.insert(
"Create Test Account",
accountId2,
- u -> u.addExternalId(ExternalId.create(gerritExtIdKey, accountId2)));
+ u -> u.addExternalId(externalIdFactory.create(gerritExtIdKey, accountId2)));
// Try to link the email to the second account (via a new MAILTO external ID) and expect that
// this fails because the email is already assigned to the first account.
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AccountException thrown =
assertThrows(AccountException.class, () -> accountManager.link(accountId2, who));
assertThat(thrown)
@@ -630,13 +660,15 @@
// Create an account with an SCHEME_EXTERNAL external ID that occupies the email.
String username = "foo";
Account.Id accountId = Account.id(seq.nextAccountId());
- ExternalId.Key externalExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_EXTERNAL, username);
+ ExternalId.Key externalExtIdKey =
+ externalIdKeyFactory.create(ExternalId.SCHEME_EXTERNAL, username);
accountsUpdate.insert(
"Create Test Account",
accountId,
- u -> u.addExternalId(ExternalId.createWithEmail(externalExtIdKey, accountId, email)));
+ u ->
+ u.addExternalId(externalIdFactory.createWithEmail(externalExtIdKey, accountId, email)));
- AuthRequest who = AuthRequest.forEmail(email);
+ AuthRequest who = authRequestFactory.createForEmail(email);
AuthResult result = accountManager.link(accountId, who);
assertThat(result.isNew()).isFalse();
assertThat(result.getAccountId().get()).isEqualTo(accountId.get());
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 5c5d127..59011f6 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -99,10 +99,12 @@
import com.google.gerrit.entities.LabelFunction;
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.LegacySubmitRequirement;
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
import com.google.gerrit.entities.RefNames;
+import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.entities.SubmitRequirement;
import com.google.gerrit.entities.SubmitRequirementExpression;
import com.google.gerrit.entities.SubmitRequirementExpressionResult;
@@ -127,7 +129,6 @@
import com.google.gerrit.extensions.api.changes.ReviewerInput;
import com.google.gerrit.extensions.api.changes.ReviewerResult;
import com.google.gerrit.extensions.api.changes.RevisionApi;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.api.groups.GroupApi;
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.api.projects.ConfigInput;
@@ -149,7 +150,9 @@
import com.google.gerrit.extensions.common.CommitInfo;
import com.google.gerrit.extensions.common.GitPerson;
import com.google.gerrit.extensions.common.LabelInfo;
+import com.google.gerrit.extensions.common.LegacySubmitRequirementInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
+import com.google.gerrit.extensions.common.SubmitRecordInfo;
import com.google.gerrit.extensions.common.SubmitRequirementResultInfo;
import com.google.gerrit.extensions.common.SubmitRequirementResultInfo.Status;
import com.google.gerrit.extensions.common.TrackingIdInfo;
@@ -170,6 +173,7 @@
import com.google.gerrit.server.change.ChangeMessages;
import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.testing.TestChangeETagComputation;
+import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
import com.google.gerrit.server.git.ChangeMessageModifier;
import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.index.change.ChangeIndex;
@@ -186,6 +190,7 @@
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder.ChangeOperatorFactory;
import com.google.gerrit.server.restapi.change.PostReview;
+import com.google.gerrit.server.rules.SubmitRule;
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
@@ -4033,6 +4038,51 @@
}
@Test
+ public void submitRecords() throws Exception {
+ PushOneCommit.Result r = createChange();
+ TestSubmitRule testSubmitRule = new TestSubmitRule();
+ try (Registration registration = extensionRegistry.newRegistration().add(testSubmitRule)) {
+ String changeId = r.getChangeId();
+
+ ChangeInfo change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRecords).hasSize(2);
+ // Check the default submit record for the code-review label
+ SubmitRecordInfo codeReviewRecord = Iterables.get(change.submitRecords, 0);
+ assertThat(codeReviewRecord.ruleName).isEqualTo("gerrit~DefaultSubmitRule");
+ assertThat(codeReviewRecord.status).isEqualTo(SubmitRecordInfo.Status.NOT_READY);
+ assertThat(codeReviewRecord.labels).hasSize(1);
+ SubmitRecordInfo.Label label = Iterables.getOnlyElement(codeReviewRecord.labels);
+ assertThat(label.label).isEqualTo("Code-Review");
+ assertThat(label.status).isEqualTo(SubmitRecordInfo.Label.Status.NEED);
+ assertThat(label.appliedBy).isNull();
+ // Check the custom test record created by the TestSubmitRule
+ SubmitRecordInfo testRecord = Iterables.get(change.submitRecords, 1);
+ assertThat(testRecord.ruleName).isEqualTo("gerrit~TestSubmitRule");
+ assertThat(testRecord.status).isEqualTo(SubmitRecordInfo.Status.OK);
+ assertThat(testRecord.requirements)
+ .containsExactly(new LegacySubmitRequirementInfo("OK", "fallback text", "type"));
+ assertThat(testRecord.labels).hasSize(1);
+ SubmitRecordInfo.Label testLabel = Iterables.getOnlyElement(testRecord.labels);
+ assertThat(testLabel.label).isEqualTo("label");
+ assertThat(testLabel.status).isEqualTo(SubmitRecordInfo.Label.Status.OK);
+ assertThat(testLabel.appliedBy).isNull();
+
+ voteLabel(changeId, "code-review", 2);
+ // Code review record is satisfied after voting +2
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRecords).hasSize(2);
+ codeReviewRecord = Iterables.get(change.submitRecords, 0);
+ assertThat(codeReviewRecord.ruleName).isEqualTo("gerrit~DefaultSubmitRule");
+ assertThat(codeReviewRecord.status).isEqualTo(SubmitRecordInfo.Status.OK);
+ assertThat(codeReviewRecord.labels).hasSize(1);
+ label = Iterables.getOnlyElement(codeReviewRecord.labels);
+ assertThat(label.label).isEqualTo("Code-Review");
+ assertThat(label.status).isEqualTo(SubmitRecordInfo.Label.Status.OK);
+ assertThat(label.appliedBy._accountId).isEqualTo(admin.id().get());
+ }
+ }
+
+ @Test
public void submitRequirement_withLabelEqualsMax() throws Exception {
configSubmitRequirement(
project,
@@ -4048,12 +4098,54 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 2);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
+ }
+
+ @Test
+ public void submitRequirement_withLabelEqualsMax_fromNonUploader() throws Exception {
+ configLabel("my-label", LabelFunction.NO_OP); // label function has no effect
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allowLabel("my-label").ref("refs/heads/master").group(REGISTERED_USERS).range(-1, 1))
+ .update();
+ configSubmitRequirement(
+ project,
+ SubmitRequirement.builder()
+ .setName("my-label")
+ .setSubmittabilityExpression(
+ SubmitRequirementExpression.create("label:my-label=MAX,user=non_uploader"))
+ .setAllowOverrideInChildProjects(false)
+ .build());
+
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ ChangeInfo change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+ // Voting with a max vote as the uploader will not satisfy the submit requirement.
+ voteLabel(changeId, "my-label", 1);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+ // Voting as a non-uploader will satisfy the submit requirement.
+ requestScopeOperations.setApiUser(user.id());
+ voteLabel(changeId, "my-label", 1);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4073,19 +4165,70 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
// Requirement is satisfied because there are no votes
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", -1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
// Requirement is still satisfied because -1 is not the max negative value
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", -2);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
// Requirement is now unsatisfied because -2 is the max negative value
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
+ }
+
+ @Test
+ public void submitRequirement_withMaxWithBlock_ignoringSelfApproval() throws Exception {
+ configLabel("my-label", LabelFunction.MAX_WITH_BLOCK);
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allowLabel("my-label").ref("refs/heads/master").group(REGISTERED_USERS).range(-1, 1))
+ .update();
+
+ configSubmitRequirement(
+ project,
+ SubmitRequirement.builder()
+ .setName("my-label")
+ .setSubmittabilityExpression(
+ SubmitRequirementExpression.create(
+ "label:my-label=MAX,user=non_uploader -label:my-label=MIN"))
+ .setAllowOverrideInChildProjects(false)
+ .build());
+
+ // Create the change as admin
+ requestScopeOperations.setApiUser(admin.id());
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+
+ // Admin (a.k.a uploader) adds a -1 min vote. This is going to block submission.
+ voteLabel(changeId, "my-label", -1);
+ ChangeInfo change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+ // user (i.e. non_uploader) votes 1. Requirement is still blocking because of -1 of uploader.
+ requestScopeOperations.setApiUser(user.id());
+ voteLabel(changeId, "my-label", 1);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.UNSATISFIED, /* isLegacy= */ false);
+
+ // Admin (a.k.a uploader) removes -1. Now requirement is fulfilled.
+ requestScopeOperations.setApiUser(admin.id());
+ voteLabel(changeId, "my-label", 0);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "my-label", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4104,12 +4247,14 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4135,15 +4280,19 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(2);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
- assertSubmitRequirementStatus(change.submitRequirements, "verified", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "verified", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 2);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(2);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
- assertSubmitRequirementStatus(change.submitRequirements, "verified", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "verified", Status.UNSATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4163,7 +4312,8 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.NOT_APPLICABLE);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.NOT_APPLICABLE, /* isLegacy= */ false);
}
@Test
@@ -4192,13 +4342,15 @@
String changeId = r.getChangeId();
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "build-cop-override", 1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.OVERRIDDEN);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.OVERRIDDEN, /* isLegacy= */ false);
}
@Test
@@ -4227,17 +4379,20 @@
String changeId = r.getChangeId();
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 2);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4255,12 +4410,14 @@
String changeId = r.getChangeId();
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
@@ -4290,47 +4447,56 @@
String changeId = r.getChangeId();
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 1);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
// +1 was enough to fulfill the requirement: override in child project was ignored
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
}
@Test
public void submitRequirement_storedForClosedChanges() throws Exception {
- configSubmitRequirement(
- project,
- SubmitRequirement.builder()
- .setName("code-review")
- .setSubmittabilityExpression(SubmitRequirementExpression.create("label:code-review=+2"))
- .setAllowOverrideInChildProjects(false)
- .build());
+ for (SubmitType submitType : SubmitType.values()) {
+ Project.NameKey project = createProjectForPush(submitType);
+ TestRepository<InMemoryRepository> repo = cloneProject(project);
+ configSubmitRequirement(
+ project,
+ SubmitRequirement.builder()
+ .setName("code-review")
+ .setSubmittabilityExpression(
+ SubmitRequirementExpression.create("label:code-review=+2"))
+ .setAllowOverrideInChildProjects(false)
+ .build());
- PushOneCommit.Result r = createChange("Add a file", "foo", "content");
- String changeId = r.getChangeId();
+ PushOneCommit.Result r =
+ createChange(repo, "master", "Add a file", "foo", "content", "topic");
+ String changeId = r.getChangeId();
- voteLabel(changeId, "code-review", 2);
+ voteLabel(changeId, "code-review", 2);
- ChangeInfo change = gApi.changes().id(changeId).get();
- assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ ChangeInfo change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(1);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
- RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
- revision.review(ReviewInput.approve());
- revision.submit();
+ RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
+ revision.review(ReviewInput.approve());
+ revision.submit();
- ChangeNotes notes = notesFactory.create(project, r.getChange().getId());
+ ChangeNotes notes = notesFactory.create(project, r.getChange().getId());
- SubmitRequirementResult result =
- notes.getSubmitRequirementsResult().stream().collect(MoreCollectors.onlyElement());
- assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.SATISFIED);
- assertThat(result.submittabilityExpressionResult().status())
- .isEqualTo(SubmitRequirementExpressionResult.Status.PASS);
- assertThat(result.submittabilityExpressionResult().expression().expressionString())
- .isEqualTo("label:code-review=+2");
+ SubmitRequirementResult result =
+ notes.getSubmitRequirementsResult().stream().collect(MoreCollectors.onlyElement());
+ assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.SATISFIED);
+ assertThat(result.submittabilityExpressionResult().status())
+ .isEqualTo(SubmitRequirementExpressionResult.Status.PASS);
+ assertThat(result.submittabilityExpressionResult().expression().expressionString())
+ .isEqualTo("label:code-review=+2");
+ }
}
@Test
@@ -4348,13 +4514,15 @@
ChangeInfo change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.UNSATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.UNSATISFIED, /* isLegacy= */ false);
voteLabel(changeId, "code-review", 2);
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
gApi.changes().id(changeId).current().submit();
@@ -4370,7 +4538,64 @@
// The new "verified" submit requirement is not returned, since this change is closed
change = gApi.changes().id(changeId).get();
assertThat(change.submitRequirements).hasSize(1);
- assertSubmitRequirementStatus(change.submitRequirements, "code-review", Status.SATISFIED);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "code-review", Status.SATISFIED, /* isLegacy= */ false);
+ }
+
+ @Test
+ @GerritConfig(
+ name = "experiments.enabled",
+ value =
+ ExperimentFeaturesConstants
+ .GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_LEGACY_SUBMIT_REQUIREMENTS)
+ public void submitRequirements_returnForLegacySubmitRecords_ifEnabled() throws Exception {
+ configLabel("build-cop-override", LabelFunction.MAX_WITH_BLOCK);
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(
+ allowLabel("build-cop-override")
+ .ref("refs/heads/master")
+ .group(REGISTERED_USERS)
+ .range(-1, 1))
+ .update();
+
+ // 1. Project has two legacy requirements: Code-Review and bco. Both unsatisfied.
+ PushOneCommit.Result r = createChange();
+ String changeId = r.getChangeId();
+ ChangeInfo change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(2);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "Code-Review", Status.UNSATISFIED, /* isLegacy= */ true);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "build-cop-override", Status.UNSATISFIED, /* isLegacy= */ true);
+
+ // 2. Vote +1 on bco. bco becomes satisfied
+ voteLabel(changeId, "build-cop-override", 1);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(2);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "Code-Review", Status.UNSATISFIED, /* isLegacy= */ true);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "build-cop-override", Status.SATISFIED, /* isLegacy= */ true);
+
+ // 3. Vote +1 on Code-Review. Code-Review becomes satisfied
+ voteLabel(changeId, "Code-Review", 2);
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(2);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "Code-Review", Status.SATISFIED, /* isLegacy= */ true);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "build-cop-override", Status.SATISFIED, /* isLegacy= */ true);
+
+ // 4. Merge the change. Submit requirements status is presented from NoteDb.
+ gApi.changes().id(changeId).current().submit();
+ change = gApi.changes().id(changeId).get();
+ assertThat(change.submitRequirements).hasSize(2);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "Code-Review", Status.SATISFIED, /* isLegacy= */ true);
+ assertSubmitRequirementStatus(
+ change.submitRequirements, "build-cop-override", Status.SATISFIED, /* isLegacy= */ true);
}
@Test
@@ -4397,7 +4622,10 @@
.get();
assertThat(changeInfos).hasSize(1);
assertSubmitRequirementStatus(
- changeInfos.get(0).submitRequirements, "code-review", Status.SATISFIED);
+ changeInfos.get(0).submitRequirements,
+ "code-review",
+ Status.SATISFIED,
+ /* isLegacy= */ false);
}
@Test
@@ -4425,7 +4653,10 @@
.get();
assertThat(changeInfos).hasSize(1);
assertSubmitRequirementStatus(
- changeInfos.get(0).submitRequirements, "code-review", Status.SATISFIED);
+ changeInfos.get(0).submitRequirements,
+ "code-review",
+ Status.SATISFIED,
+ /* isLegacy= */ false);
}
@Test
@@ -4747,6 +4978,28 @@
}
@Test
+ @GerritConfig(name = "trackingid.jira-bug.footer", value = "Bug:")
+ @GerritConfig(name = "trackingid.jira-bug.match", value = "\\d+")
+ @GerritConfig(name = "trackingid.jira-bug.system", value = "JIRA")
+ public void multipleTrackingIdsInSingleFooter() throws Exception {
+ PushOneCommit push =
+ pushFactory.create(
+ admin.newIdent(),
+ testRepo,
+ PushOneCommit.SUBJECT + "\n\n" + "Bug: 123, 456",
+ PushOneCommit.FILE_NAME,
+ PushOneCommit.FILE_CONTENT);
+ PushOneCommit.Result result = push.to("refs/for/master");
+ result.assertOkStatus();
+
+ ChangeInfo change = gApi.changes().id(result.getChangeId()).get(TRACKING_IDS);
+ Collection<TrackingIdInfo> trackingIds = change.trackingIds;
+ assertThat(trackingIds).isNotNull();
+ assertThat(trackingIds).hasSize(2);
+ assertThat(trackingIds.stream().map(t -> t.id)).containsExactly("123", "456");
+ }
+
+ @Test
public void starUnstar() throws Exception {
ChangeIndexedCounter changeIndexedCounter = new ChangeIndexedCounter();
try (Registration registration =
@@ -4874,132 +5127,6 @@
}
@Test
- public void markAsReviewed() throws Exception {
- com.google.gerrit.acceptance.TestAccount user2 = accountCreator.user2();
-
- PushOneCommit.Result r = createChange();
-
- ReviewerInput in = new ReviewerInput();
- in.reviewer = user.email();
- gApi.changes().id(r.getChangeId()).addReviewer(in);
-
- requestScopeOperations.setApiUser(user.id());
- assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isNull();
- gApi.changes().id(r.getChangeId()).markAsReviewed(true);
- assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isTrue();
-
- requestScopeOperations.setApiUser(user2.id());
- sender.clear();
- amendChange(r.getChangeId());
-
- requestScopeOperations.setApiUser(user.id());
- assertThat(gApi.changes().id(r.getChangeId()).get().reviewed).isNull();
-
- List<Message> messages = sender.getMessages();
- assertThat(messages).hasSize(1);
- assertThat(messages.get(0).rcpt()).containsExactly(user.getNameEmail());
- }
-
- @Test
- public void cannotSetUnreviewedLabelForPatchSetThatAlreadyHasReviewedLabel() throws Exception {
- String changeId = createChange().getChangeId();
-
- requestScopeOperations.setApiUser(user.id());
- gApi.changes().id(changeId).markAsReviewed(true);
- assertThat(gApi.changes().id(changeId).get().reviewed).isTrue();
-
- BadRequestException thrown =
- assertThrows(
- BadRequestException.class,
- () ->
- gApi.accounts()
- .self()
- .setStars(
- changeId,
- new StarsInput(
- ImmutableSet.of(StarredChangesUtil.UNREVIEWED_LABEL + "/1"))));
- assertThat(thrown)
- .hasMessageThat()
- .contains(
- "The labels "
- + StarredChangesUtil.REVIEWED_LABEL
- + "/"
- + 1
- + " and "
- + StarredChangesUtil.UNREVIEWED_LABEL
- + "/"
- + 1
- + " are mutually exclusive. Only one of them can be set.");
- }
-
- @Test
- public void cannotSetReviewedLabelForPatchSetThatAlreadyHasUnreviewedLabel() throws Exception {
- String changeId = createChange().getChangeId();
-
- requestScopeOperations.setApiUser(user.id());
- gApi.changes().id(changeId).markAsReviewed(false);
- assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
-
- BadRequestException thrown =
- assertThrows(
- BadRequestException.class,
- () ->
- gApi.accounts()
- .self()
- .setStars(
- changeId,
- new StarsInput(ImmutableSet.of(StarredChangesUtil.REVIEWED_LABEL + "/1"))));
- assertThat(thrown)
- .hasMessageThat()
- .contains(
- "The labels "
- + StarredChangesUtil.REVIEWED_LABEL
- + "/"
- + 1
- + " and "
- + StarredChangesUtil.UNREVIEWED_LABEL
- + "/"
- + 1
- + " are mutually exclusive. Only one of them can be set.");
- }
-
- @Test
- public void setReviewedAndUnreviewedLabelsForDifferentPatchSets() throws Exception {
- String changeId = createChange().getChangeId();
-
- requestScopeOperations.setApiUser(user.id());
- gApi.changes().id(changeId).markAsReviewed(true);
- assertThat(gApi.changes().id(changeId).get().reviewed).isTrue();
-
- amendChange(changeId);
- assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
-
- gApi.changes().id(changeId).markAsReviewed(false);
- assertThat(gApi.changes().id(changeId).get().reviewed).isNull();
-
- assertThat(gApi.accounts().self().getStars(changeId))
- .containsExactly(
- StarredChangesUtil.REVIEWED_LABEL + "/" + 1,
- StarredChangesUtil.UNREVIEWED_LABEL + "/" + 2);
- }
-
- @Test
- public void cannotSetInvalidLabel() throws Exception {
- String changeId = createChange().getChangeId();
-
- // label cannot contain whitespace
- String invalidLabel = "invalid label";
- BadRequestException thrown =
- assertThrows(
- BadRequestException.class,
- () ->
- gApi.accounts()
- .self()
- .setStars(changeId, new StarsInput(ImmutableSet.of(invalidLabel))));
- assertThat(thrown).hasMessageThat().contains("invalid labels: " + invalidLabel);
- }
-
- @Test
public void changeDetailsDoesNotRequireIndex() throws Exception {
// This set of options must be kept in sync with gr-rest-api-interface.js
Set<ListChangesOption> options =
@@ -5077,9 +5204,12 @@
private void assertSubmitRequirementStatus(
Collection<SubmitRequirementResultInfo> results,
String requirementName,
- SubmitRequirementResultInfo.Status status) {
+ SubmitRequirementResultInfo.Status status,
+ boolean isLegacy) {
for (SubmitRequirementResultInfo result : results) {
- if (result.name.equals(requirementName) && result.status == status) {
+ if (result.name.equals(requirementName)
+ && result.status == status
+ && result.isLegacy == isLegacy) {
return;
}
}
@@ -5092,4 +5222,36 @@
.map(r -> String.format("%s=%s", r.name, r.status))
.collect(toImmutableList())));
}
+
+ private Project.NameKey createProjectForPush(SubmitType submitType) throws Exception {
+ Project.NameKey project = projectOperations.newProject().submitType(submitType).create();
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(allow(Permission.PUSH).ref("refs/heads/*").group(adminGroupUuid()))
+ .add(allow(Permission.SUBMIT).ref("refs/for/refs/heads/*").group(adminGroupUuid()))
+ .update();
+ return project;
+ }
+
+ /** Returns a hard-coded submit record containing all fields. */
+ private static class TestSubmitRule implements SubmitRule {
+ @Override
+ public Optional<SubmitRecord> evaluate(ChangeData changeData) {
+ SubmitRecord record = new SubmitRecord();
+ record.ruleName = "testSubmitRule";
+ record.status = SubmitRecord.Status.OK;
+ SubmitRecord.Label label = new SubmitRecord.Label();
+ label.label = "label";
+ label.status = SubmitRecord.Label.Status.OK;
+ record.labels = Arrays.asList(label);
+ record.requirements =
+ Arrays.asList(
+ LegacySubmitRequirement.builder()
+ .setType("type")
+ .setFallbackText("fallback text")
+ .build());
+ return Optional.of(record);
+ }
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java b/javatests/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
index df281d9..cd9e876 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/StickyApprovalsIT.java
@@ -14,6 +14,7 @@
package com.google.gerrit.acceptance.api.change;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowLabel;
@@ -28,13 +29,16 @@
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.server.project.testing.TestLabels.labelBuilder;
import static com.google.gerrit.server.project.testing.TestLabels.value;
+import static java.util.Comparator.comparing;
import com.google.common.cache.Cache;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.TestProjectInput;
import com.google.gerrit.acceptance.testsuite.change.ChangeKindCreator;
import com.google.gerrit.acceptance.testsuite.change.ChangeOperations;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
@@ -43,17 +47,21 @@
import com.google.gerrit.entities.LabelId;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.PatchSet;
+import com.google.gerrit.entities.PatchSetApproval;
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
import com.google.gerrit.extensions.client.ChangeKind;
import com.google.gerrit.extensions.common.ApprovalInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
+import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.server.change.ChangeKindCacheImpl;
import com.google.gerrit.server.project.testing.TestLabels;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import java.util.EnumSet;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
@@ -439,6 +447,64 @@
@Test
public void
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileAlreadyExists_withoutCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileAlreadyExists();
+ }
+
+ @Test
+ public void
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileAlreadyExists_withCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileAlreadyExists();
+ }
+
+ private void notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileAlreadyExists()
+ throws Exception {
+ // create "existing file" and submit it.
+ String existingFile = "existing file";
+ Change.Id prep =
+ changeOperations
+ .newChange()
+ .project(project)
+ .file(existingFile)
+ .content("content")
+ .create();
+ vote(admin, prep.toString(), 2, 1);
+ gApi.changes().id(prep.get()).current().submit();
+
+ Change.Id changeId = changeOperations.newChange().project(project).create();
+ vote(admin, changeId.toString(), 2, 1);
+ vote(user, changeId.toString(), -2, -1);
+
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .file(existingFile)
+ .content("new content")
+ .create();
+ ChangeInfo c = detailedChange(changeId.toString());
+
+ // no votes are copied since the list of files changed ("existing file" was added to the
+ // change).
+ assertVotes(c, admin, 0, 0);
+ assertVotes(c, user, 0, 0);
+ }
+
+ @Test
+ public void
notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsDeleted_withoutCopyCondition()
throws Exception {
try (ProjectConfigUpdate u = updateProject(project)) {
@@ -517,6 +583,94 @@
assertVotes(c, user, -2, 0);
}
+ @TestProjectInput(createEmptyCommit = false)
+ public void
+ stickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedAsInitialCommit_withoutCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ stickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedAsInitialCommit();
+ }
+
+ @TestProjectInput(createEmptyCommit = false)
+ public void
+ stickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedAsInitialCommit_withCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ stickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedAsInitialCommit();
+ }
+
+ private void stickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedAsInitialCommit()
+ throws Exception {
+ Change.Id changeId =
+ changeOperations.newChange().project(project).file("file").content("content").create();
+ vote(admin, changeId.toString(), 2, 1);
+ vote(user, changeId.toString(), -2, -1);
+
+ changeOperations.change(changeId).newPatchset().file("file").content("new content").create();
+ ChangeInfo c = detailedChange(changeId.toString());
+
+ // only code review votes are copied since copyAllScoresIfListOfFilesDidNotChange is
+ // configured for that label, and list of files didn't change.
+ assertVotes(c, admin, 2, 0);
+ assertVotes(c, user, -2, 0);
+ }
+
+ @Test
+ public void
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedOnEarlierPatchset_withoutCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedOnEarlierPatchset();
+ }
+
+ @Test
+ public void
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedOnEarlierPatchset_withCopyCondition()
+ throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedOnEarlierPatchset();
+ }
+
+ private void
+ notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsModifiedOnEarlierPatchset()
+ throws Exception {
+ Change.Id changeId =
+ changeOperations.newChange().project(project).file("file").content("content").create();
+ vote(admin, changeId.toString(), 2, 1);
+ vote(user, changeId.toString(), -2, -1);
+
+ changeOperations.change(changeId).newPatchset().file("new file").content("content").create();
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .file("new file")
+ .content("new content")
+ .create();
+ ChangeInfo c = detailedChange(changeId.toString());
+
+ // Don't copy over votes since ps1->ps2 should copy over, but ps2->ps3 should not.
+ assertVotes(c, admin, 0, 0);
+ assertVotes(c, user, 0, 0);
+ }
+
@Test
public void
notStickyWithCopyAllScoresIfListOfFilesDidNotChangeWhenFileIsRenamed_withoutCopyCondition()
@@ -687,6 +841,120 @@
}
@Test
+ public void copyWithListOfFilesUnchanged_withoutCopyCondition() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(
+ LabelId.CODE_REVIEW, b -> b.setCopyAllScoresIfListOfFilesDidNotChange(true));
+ u.save();
+ }
+ copyWithListOfFilesUnchanged();
+ }
+
+ @Test
+ public void copyWithListOfFilesUnchanged_withCopyCondition() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ copyWithListOfFilesUnchanged();
+ }
+
+ private void copyWithListOfFilesUnchanged() throws Exception {
+ Change.Id changeId =
+ changeOperations.newChange().project(project).file("file").content("content").create();
+ vote(admin, changeId.toString(), 2, 1);
+ vote(user, changeId.toString(), -2, -1);
+
+ changeOperations.change(changeId).newPatchset().file("file").content("new content").create();
+ ChangeInfo c = detailedChange(changeId.toString());
+
+ // Code-Review votes are copied over from ps1-> ps2 since the list of files were unchanged.
+ assertVotes(c, admin, 2, 0);
+ assertVotes(c, user, -2, 0);
+
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .file("file")
+ .content("very new content")
+ .create();
+ c = detailedChange(changeId.toString());
+
+ // Code-Review votes are copied over from ps1-> ps3 since the list of files were unchanged.
+ assertVotes(c, admin, 2, 0);
+ assertVotes(c, user, -2, 0);
+
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .file("new file")
+ .content("new content")
+ .create();
+
+ c = detailedChange(changeId.toString());
+ // Code-Review votes are not copied over from ps1-> ps4 since a file was added.
+ assertVotes(c, admin, 0, 0);
+ assertVotes(c, user, 0, 0);
+
+ changeOperations.change(changeId).newPatchset().file("file").content("content").create();
+
+ c = detailedChange(changeId.toString());
+ // Code-Review votes are not copied over from ps1 -> ps5 since a file was added on ps4.
+ // Although the list of files is the same between ps4->ps5, we don't copy votes from before
+ // ps4.
+ assertVotes(c, admin, 0, 0);
+ assertVotes(c, user, 0, 0);
+ }
+
+ @Test
+ public void copyWithListOfFilesUnchangedButAddedMergeList() throws Exception {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig()
+ .updateLabelType(LabelId.CODE_REVIEW, b -> b.setCopyCondition("has:unchanged-files"));
+ u.save();
+ }
+ Change.Id parent1ChangeId = changeOperations.newChange().create();
+ Change.Id parent2ChangeId = changeOperations.newChange().create();
+ Change.Id dummyParentChangeId = changeOperations.newChange().create();
+ Change.Id changeId =
+ changeOperations
+ .newChange()
+ .mergeOf()
+ .change(parent1ChangeId)
+ .and()
+ .change(parent2ChangeId)
+ .create();
+
+ Map<String, FileInfo> changedFilesFirstPatchset =
+ gApi.changes().id(changeId.get()).current().files();
+
+ assertThat(changedFilesFirstPatchset.keySet()).containsExactly("/COMMIT_MSG", "/MERGE_LIST");
+
+ // Make a Code-Review vote that should be sticky.
+ gApi.changes().id(changeId.get()).current().review(ReviewInput.approve());
+
+ changeOperations
+ .change(changeId)
+ .newPatchset()
+ .parent()
+ .patchset(PatchSet.id(dummyParentChangeId, 1))
+ .create();
+
+ Map<String, FileInfo> changedFilesSecondPatchset =
+ gApi.changes().id(changeId.get()).current().files();
+
+ // Only "/MERGE_LIST" was removed.
+ assertThat(changedFilesSecondPatchset.keySet()).containsExactly("/COMMIT_MSG");
+ ApprovalInfo approvalInfo =
+ Iterables.getOnlyElement(
+ gApi.changes().id(changeId.get()).current().votes().get(LabelId.CODE_REVIEW));
+ assertThat(approvalInfo._accountId).isEqualTo(admin.id().get());
+ assertThat(approvalInfo.value).isEqualTo(2);
+ }
+
+ @Test
public void deleteStickyVote() throws Exception {
String label = LabelId.CODE_REVIEW;
try (ProjectConfigUpdate u = updateProject(project)) {
@@ -733,6 +1001,237 @@
assertThat(r.getChange().approvals().get(PatchSet.id(r.getChange().getId(), 2))).hasSize(1);
}
+ @Test
+ public void stickyVoteStoredOnUpload() throws Exception {
+ // Code-Review will be sticky.
+ String label = LabelId.CODE_REVIEW;
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
+ u.save();
+ }
+
+ PushOneCommit.Result r = createChange();
+ // Add a new vote.
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 2);
+ input.tag = "tag";
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Make new patchsets, keeping the Code-Review +2 vote.
+ for (int i = 0; i < 9; i++) {
+ amendChange(r.getChangeId());
+ }
+
+ List<PatchSetApproval> patchSetApprovals =
+ r.getChange().notes().getApprovalsWithCopied().values().stream()
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList());
+
+ for (int i = 0; i < 10; i++) {
+ int patchSet = i + 1;
+ assertThat(patchSetApprovals.get(i).patchSetId().get()).isEqualTo(patchSet);
+ assertThat(patchSetApprovals.get(i).accountId().get()).isEqualTo(admin.id().get());
+ assertThat(patchSetApprovals.get(i).realAccountId().get()).isEqualTo(admin.id().get());
+ assertThat(patchSetApprovals.get(i).label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(patchSetApprovals.get(i).value()).isEqualTo((short) 2);
+ assertThat(patchSetApprovals.get(i).tag().get()).isEqualTo("tag");
+ if (patchSet == 1) {
+ assertThat(patchSetApprovals.get(i).copied()).isFalse();
+ } else {
+ assertThat(patchSetApprovals.get(i).copied()).isTrue();
+ }
+ }
+ }
+
+ @Test
+ public void stickyVoteStoredOnRebase() throws Exception {
+ // Code-Review will be sticky.
+ String label = LabelId.CODE_REVIEW;
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
+ u.save();
+ }
+
+ // Create two changes both with the same parent
+ PushOneCommit.Result r = createChange();
+ testRepo.reset("HEAD~1");
+ PushOneCommit.Result r2 = createChange();
+
+ // Approve and submit the first change
+ RevisionApi revision = gApi.changes().id(r.getChangeId()).current();
+ revision.review(ReviewInput.approve().label(LabelId.VERIFIED, 1));
+ revision.submit();
+
+ // Add an approval whose score should be copied.
+ gApi.changes().id(r2.getChangeId()).current().review(ReviewInput.recommend());
+
+ // Rebase the second change
+ gApi.changes().id(r2.getChangeId()).rebase();
+
+ List<PatchSetApproval> patchSetApprovals =
+ r2.getChange().notes().getApprovalsWithCopied().values().stream()
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList());
+ PatchSetApproval nonCopied = patchSetApprovals.get(0);
+
+ assertThat(nonCopied.patchSetId().get()).isEqualTo(1);
+ assertThat(nonCopied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(nonCopied.value()).isEqualTo((short) 1);
+ assertThat(nonCopied.copied()).isFalse();
+
+ PatchSetApproval copied = patchSetApprovals.get(1);
+ assertThat(copied.patchSetId().get()).isEqualTo(2);
+ assertThat(copied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(copied.value()).isEqualTo((short) 1);
+ assertThat(copied.copied()).isTrue();
+ }
+
+ @Test
+ public void stickyVoteStoredOnUploadWithRealAccount() throws Exception {
+ // Give "user" permission to vote on behalf of other users.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(
+ allowLabel(TestLabels.codeReview().getName())
+ .impersonation(true)
+ .ref("refs/heads/*")
+ .group(REGISTERED_USERS)
+ .range(-1, 1))
+ .update();
+
+ // Code-Review will be sticky.
+ String label = LabelId.CODE_REVIEW;
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
+ u.save();
+ }
+
+ PushOneCommit.Result r = createChange();
+
+ // Add a new vote as user
+ requestScopeOperations.setApiUser(user.id());
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 1);
+ input.onBehalfOf = admin.email();
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Make a new patchset, keeping the Code-Review +1 vote.
+ amendChange(r.getChangeId());
+
+ List<PatchSetApproval> patchSetApprovals =
+ r.getChange().notes().getApprovalsWithCopied().values().stream()
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList());
+
+ PatchSetApproval nonCopied = patchSetApprovals.get(0);
+ assertThat(nonCopied.patchSetId().get()).isEqualTo(1);
+ assertThat(nonCopied.accountId().get()).isEqualTo(admin.id().get());
+ assertThat(nonCopied.realAccountId().get()).isEqualTo(user.id().get());
+ assertThat(nonCopied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(nonCopied.value()).isEqualTo((short) 1);
+ assertThat(nonCopied.copied()).isFalse();
+
+ PatchSetApproval copied = patchSetApprovals.get(1);
+ assertThat(copied.patchSetId().get()).isEqualTo(2);
+ assertThat(copied.accountId().get()).isEqualTo(admin.id().get());
+ assertThat(copied.realAccountId().get()).isEqualTo(user.id().get());
+ assertThat(copied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(copied.value()).isEqualTo((short) 1);
+ assertThat(copied.copied()).isTrue();
+ }
+
+ @Test
+ public void stickyVoteStoredOnUploadWithRealAccountAndTag() throws Exception {
+ // Give "user" permission to vote on behalf of other users.
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(
+ allowLabel(TestLabels.codeReview().getName())
+ .impersonation(true)
+ .ref("refs/heads/*")
+ .group(REGISTERED_USERS)
+ .range(-1, 1))
+ .update();
+
+ // Code-Review will be sticky.
+ String label = LabelId.CODE_REVIEW;
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
+ u.save();
+ }
+
+ PushOneCommit.Result r = createChange();
+
+ // Add a new vote as user
+ requestScopeOperations.setApiUser(user.id());
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 1);
+ input.onBehalfOf = admin.email();
+ input.tag = "tag";
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Make a new patchset, keeping the Code-Review +1 vote.
+ amendChange(r.getChangeId());
+
+ List<PatchSetApproval> patchSetApprovals =
+ r.getChange().notes().getApprovalsWithCopied().values().stream()
+ .sorted(comparing(a -> a.patchSetId().get()))
+ .collect(toImmutableList());
+
+ PatchSetApproval nonCopied = patchSetApprovals.get(0);
+ assertThat(nonCopied.patchSetId().get()).isEqualTo(1);
+ assertThat(nonCopied.accountId().get()).isEqualTo(admin.id().get());
+ assertThat(nonCopied.realAccountId().get()).isEqualTo(user.id().get());
+ assertThat(nonCopied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(nonCopied.value()).isEqualTo((short) 1);
+ assertThat(nonCopied.tag().get()).isEqualTo("tag");
+ assertThat(nonCopied.copied()).isFalse();
+
+ PatchSetApproval copied = patchSetApprovals.get(1);
+ assertThat(copied.patchSetId().get()).isEqualTo(2);
+ assertThat(copied.accountId().get()).isEqualTo(admin.id().get());
+ assertThat(copied.realAccountId().get()).isEqualTo(user.id().get());
+ assertThat(copied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(copied.value()).isEqualTo((short) 1);
+ assertThat(nonCopied.tag().get()).isEqualTo("tag");
+ assertThat(copied.copied()).isTrue();
+ }
+
+ @Test
+ public void stickyVoteStoredCanBeRemoved() throws Exception {
+ // Code-Review will be sticky.
+ String label = LabelId.CODE_REVIEW;
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().updateLabelType(label, b -> b.setCopyAnyScore(true));
+ u.save();
+ }
+
+ PushOneCommit.Result r = createChange();
+
+ // Add a new vote
+ ReviewInput input = new ReviewInput().label(LabelId.CODE_REVIEW, 2);
+ gApi.changes().id(r.getChangeId()).current().review(input);
+
+ // Make a new patchset, keeping the Code-Review +2 vote.
+ amendChange(r.getChangeId());
+ assertVotes(detailedChange(r.getChangeId()), admin, label, 2, null);
+
+ gApi.changes().id(r.getChangeId()).current().review(ReviewInput.noScore());
+
+ PatchSetApproval nonCopiedSecondPatchsetRemovedVote =
+ Iterables.getOnlyElement(
+ r.getChange()
+ .notes()
+ .getApprovalsWithCopied()
+ .get(r.getChange().change().currentPatchSetId()));
+
+ assertThat(nonCopiedSecondPatchsetRemovedVote.patchSetId().get()).isEqualTo(2);
+ assertThat(nonCopiedSecondPatchsetRemovedVote.accountId().get()).isEqualTo(admin.id().get());
+ assertThat(nonCopiedSecondPatchsetRemovedVote.label()).isEqualTo(LabelId.CODE_REVIEW);
+ // The vote got removed since the latest patch-set only has one vote and it's "0".
+ assertThat(nonCopiedSecondPatchsetRemovedVote.value()).isEqualTo((short) 0);
+ assertThat(nonCopiedSecondPatchsetRemovedVote.copied()).isFalse();
+ }
+
private void assertChangeKindCacheContains(ObjectId prior, ObjectId next) {
ChangeKind kind =
changeKindCache.getIfPresent(ChangeKindCacheImpl.Key.create(prior, next, "recursive"));
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
index bc9f50a5..636b71d 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitRuleIT.java
@@ -27,6 +27,7 @@
import com.google.gerrit.server.project.SubmitRuleOptions;
import com.google.inject.Inject;
import java.util.List;
+import java.util.stream.Collectors;
import org.junit.Test;
public class SubmitRuleIT extends AbstractDaemonTest {
@@ -39,6 +40,11 @@
PushOneCommit.Result r = createChange();
approve(r.getChangeId());
List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ assertThat(
+ recordsBeforeSubmission.stream()
+ .map(record -> record.ruleName)
+ .collect(Collectors.toList()))
+ .containsExactly("gerrit~DefaultSubmitRule");
gApi.changes().id(r.getChangeId()).current().submit();
// Add a new label that blocks submission if not granted. In case we reevaluate the rules,
// this would show up as blocking submission.
@@ -57,6 +63,11 @@
PushOneCommit.Result r = createChange();
approve(r.getChangeId());
List<SubmitRecord> recordsBeforeSubmission = submitRuleEvaluator.evaluate(r.getChange());
+ assertThat(
+ recordsBeforeSubmission.stream()
+ .map(record -> record.ruleName)
+ .collect(Collectors.toList()))
+ .containsExactly("gerrit~DefaultSubmitRule");
gApi.changes().id(r.getChangeId()).current().submit();
// Add a new label that blocks submission if not granted. In case we reevaluate the rules,
// this would show up as blocking submission.
diff --git a/javatests/com/google/gerrit/acceptance/api/change/SubmitWithStickyApprovalDiffIT.java b/javatests/com/google/gerrit/acceptance/api/change/SubmitWithStickyApprovalDiffIT.java
index 607fbc0..5124d11 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/SubmitWithStickyApprovalDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/SubmitWithStickyApprovalDiffIT.java
@@ -37,6 +37,8 @@
import com.google.gerrit.extensions.api.changes.ReviewInput.CommentInput;
import com.google.gerrit.server.project.testing.TestLabels;
import com.google.inject.Inject;
+import java.util.HashSet;
+import java.util.Set;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Before;
import org.junit.Test;
@@ -602,22 +604,38 @@
int deletions2,
String expectedFileDiff2,
String oldFileName2) {
- String expectedMessage =
+ String beginningOfMessage =
"1 is the latest approved patch-set.\n"
+ "The change was submitted with unreviewed changes in the following files:\n"
+ "\n";
- expectedMessage += fileDiff(expectedFileDiff1, oldFileName1, file1, insertions1, deletions1);
- expectedMessage += fileDiff(expectedFileDiff2, oldFileName2, file2, insertions2, deletions2);
- String expectedChangeMessage = "Change has been successfully merged\n\n" + expectedMessage;
- assertThat(message.trim()).isEqualTo(expectedChangeMessage.trim());
- assertThat(Iterables.getLast(sender.getMessages()).body()).contains(expectedMessage);
+ String fileDiff1 = fileDiff(expectedFileDiff1, oldFileName1, file1, insertions1, deletions1);
+ String expectedMessage1 = beginningOfMessage + fileDiff1;
+ String expectedMessage2 = "";
+ Set<String> expectedChangeMessages = new HashSet<>();
+ if (file2 != null) {
+ String fileDiff2 = fileDiff(expectedFileDiff2, oldFileName2, file2, insertions2, deletions2);
+ expectedMessage2 = beginningOfMessage + fileDiff2 + fileDiff1;
+ String expectedChangeMessage2 = "Change has been successfully merged\n\n" + expectedMessage2;
+ expectedMessage1 += fileDiff2;
+ expectedChangeMessages.add(expectedChangeMessage2.trim());
+ }
+ String expectedChangeMessage1 = "Change has been successfully merged\n\n" + expectedMessage1;
+ expectedChangeMessage1 = expectedChangeMessage1.trim();
+ expectedChangeMessages.add(expectedChangeMessage1.trim());
+
+ // The order of appearance in the diff for multiple files is not defined, so check both
+ // possible orders.
+ assertThat(expectedChangeMessages).contains(message.trim());
+ String email = Iterables.getLast(sender.getMessages()).body();
+ if (email.contains(expectedMessage1) || expectedMessage2.isEmpty()) {
+ assertThat(email).contains(expectedMessage1.trim());
+ } else {
+ assertThat(email).contains(expectedMessage2.trim());
+ }
}
private String fileDiff(
String expectedFileDiff, String oldFileName, String file, int insertions, int deletions) {
- if (file == null) {
- return "";
- }
String expectedMessage =
"```\n"
+ String.format("The name of the file: %s\n", file)
diff --git a/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
index bdb03d2..18e192d 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/CommitIT.java
@@ -15,7 +15,10 @@
package com.google.gerrit.acceptance.api.project;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.pushHead;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static java.util.stream.Collectors.toList;
import static org.eclipse.jgit.lib.Constants.R_TAGS;
@@ -28,6 +31,7 @@
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Permission;
+import com.google.gerrit.entities.RefNames;
import com.google.gerrit.extensions.api.changes.CherryPickInput;
import com.google.gerrit.extensions.api.changes.IncludedInInfo;
import com.google.gerrit.extensions.api.changes.ReviewInput;
@@ -99,6 +103,53 @@
}
@Test
+ public void includedInMergedChange_filtersOutNonVisibleBranches() throws Exception {
+ Result baseChange = createAndSubmitChange("refs/for/master");
+
+ createBranch(BranchNameKey.create(project, "test-branch-1"));
+ createBranch(BranchNameKey.create(project, "test-branch-2"));
+ createAndSubmitChange("refs/for/test-branch-1");
+ createAndSubmitChange("refs/for/test-branch-2");
+
+ assertThat(getIncludedIn(baseChange.getCommit().getId()).branches)
+ .containsExactly("master", "test-branch-1", "test-branch-2");
+
+ projectOperations
+ .project(project)
+ .forUpdate()
+ .add(block(Permission.READ).ref("refs/heads/test-branch-1").group(REGISTERED_USERS))
+ .update();
+
+ assertThat(getIncludedIn(baseChange.getCommit().getId()).branches)
+ .containsExactly("master", "test-branch-2");
+ }
+
+ @Test
+ public void includedInMergedChange_filtersOutNonVisibleTags() throws Exception {
+ String tagBase = "tag_base";
+ String tagBranch1 = "tag_1";
+
+ Result baseChange = createAndSubmitChange("refs/for/master");
+ createLightWeightTag(tagBase);
+ assertThat(getIncludedIn(baseChange.getCommit().getId()).tags).containsExactly(tagBase);
+
+ createBranch(BranchNameKey.create(project, "test-branch-1"));
+ createAndSubmitChange("refs/for/test-branch-1");
+ createLightWeightTag(tagBranch1);
+ assertThat(getIncludedIn(baseChange.getCommit().getId()).tags)
+ .containsExactly(tagBase, tagBranch1);
+
+ projectOperations
+ .project(project)
+ .forUpdate()
+ // Tag permissions are controlled by read permissions on branches. Blocking read permission
+ // on test-branch-1 so that tagBranch1 becomes non-visible
+ .add(block(Permission.READ).ref("refs/heads/test-branch-1").group(REGISTERED_USERS))
+ .update();
+ assertThat(getIncludedIn(baseChange.getCommit().getId()).tags).containsExactly(tagBase);
+ }
+
+ @Test
public void cherryPickWithoutMessageSameBranch() throws Exception {
String destBranch = "master";
@@ -390,4 +441,15 @@
assertThat(actual.email).isEqualTo(expected.email());
assertThat(actual.name).isEqualTo(expected.fullName());
}
+
+ private Result createAndSubmitChange(String branch) throws Exception {
+ Result r = createChange(branch);
+ approve(r.getChangeId());
+ gApi.changes().id(r.getChangeId()).current().submit();
+ return r;
+ }
+
+ private void createLightWeightTag(String tagName) throws Exception {
+ pushHead(testRepo, RefNames.REFS_TAGS + tagName, false, false);
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
index dd70d4a..c42628c 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIT.java
@@ -842,7 +842,7 @@
String otherLink = "https://other.example.com";
input = new ConfigInput();
addCommentLink(input, BUGZILLA, BUGZILLA_MATCH, otherLink);
- info = setConfig(child, input);
+ setConfig(child, input);
expected = new HashMap<>();
expected.put(BUGZILLA, commentLinkInfo(BUGZILLA, BUGZILLA_MATCH, otherLink));
@@ -866,7 +866,7 @@
String otherLink = "https://other.example.com";
input = new ConfigInput();
addCommentLink(input, BUGZILLA, BUGZILLA_MATCH, otherLink);
- info = setConfig(project, input);
+ setConfig(project, input);
expected = new HashMap<>();
expected.put(BUGZILLA, commentLinkInfo(BUGZILLA, BUGZILLA_MATCH, otherLink));
@@ -888,7 +888,7 @@
input = new ConfigInput();
addCommentLink(input, BUGZILLA, null);
- info = setConfig(project, input);
+ setConfig(project, input);
expected = new HashMap<>();
expected.put(JIRA, commentLinkInfo(JIRA, JIRA_MATCH, JIRA_LINK));
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
index bcd98d4..58dc0b0 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionDiffIT.java
@@ -50,7 +50,6 @@
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.webui.EditWebLink;
-import com.google.gerrit.server.change.FileInfoJsonExperimentImpl;
import com.google.gerrit.server.patch.DiffOperations;
import com.google.gerrit.server.patch.filediff.FileDiffOutput;
import com.google.inject.Inject;
@@ -93,8 +92,6 @@
@Inject private ProjectOperations projectOperations;
private boolean intraline;
- private boolean useNewDiffCacheListFiles;
- private boolean useNewDiffCacheGetDiff;
private ObjectId initialCommit;
private ObjectId commit1;
@@ -109,11 +106,6 @@
baseConfig.setString("cache", "diff_intraline", "timeout", "1 minute");
intraline = baseConfig.getBoolean(TEST_PARAMETER_MARKER, "intraline", false);
- useNewDiffCacheListFiles =
- Arrays.asList(baseConfig.getStringList("experiments", null, "enabled"))
- .contains(FileInfoJsonExperimentImpl.NEW_DIFF_CACHE_FEATURE);
- useNewDiffCacheGetDiff =
- baseConfig.getBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", false);
ObjectId headCommit = testRepo.getRepository().resolve("HEAD");
initialCommit = headCommit;
@@ -1325,7 +1317,7 @@
}
@Test
- public void addedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void addedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommit(commit1, "file_added_in_another_commit.txt", "Some file content");
rebaseChangeOn(changeId, commit2);
@@ -1337,7 +1329,7 @@
}
@Test
- public void removedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void removedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommitRemovingFiles(commit1, FILE_NAME2);
rebaseChangeOn(changeId, commit2);
@@ -1349,7 +1341,7 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase() throws Exception {
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase() throws Exception {
ObjectId commit2 = addCommitRenamingFile(commit1, FILE_NAME2, "a_new_file_name.txt");
rebaseChangeOn(changeId, commit2);
@@ -1361,10 +1353,10 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase_WhenEquallyModifiedInBoth()
+ @Ignore
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase_whenEquallyModifiedInBoth()
throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
- assume().that(useNewDiffCacheListFiles).isFalse();
Function<String, String> contentModification =
fileContent -> fileContent.replace("1st line\n", "First line\n");
@@ -1387,7 +1379,7 @@
}
@Test
- public void renamedUnrelatedFileIsIgnored_ForPatchSetDiffWithRebase_WhenModifiedDuringRebase()
+ public void renamedUnrelatedFileIsIgnored_forPatchSetDiffWithRebase_whenModifiedDuringRebase()
throws Exception {
String renamedFilePath = "renamed_some_file.txt";
ObjectId commit2 =
@@ -1455,9 +1447,9 @@
}
@Test
+ @Ignore
public void filesTouchedByPatchSetsAndContainingOnlyRebaseHunksAreIgnored() throws Exception {
// TODO(ghareeb): fix this test for the new diff cache implementation
- assume().that(useNewDiffCacheListFiles).isFalse();
addModifiedPatchSet(
changeId, FILE_NAME, fileContent -> fileContent.replace("Line 50\n", "Line fifty\n"));
@@ -2179,7 +2171,7 @@
}
@Test
- public void rebaseHunkInRenamedFileIsIdentified_WhenFileIsRenamedDuringRebase() throws Exception {
+ public void rebaseHunkInRenamedFileIsIdentified_whenFileIsRenamedDuringRebase() throws Exception {
String renamedFilePath = "renamed_some_file.txt";
ObjectId commit2 =
addCommit(commit1, FILE_NAME, FILE_CONTENT.replace("Line 1\n", "Line one\n"));
@@ -2208,7 +2200,7 @@
}
@Test
- public void rebaseHunkInRenamedFileIsIdentified_WhenFileIsRenamedInPatchSets() throws Exception {
+ public void rebaseHunkInRenamedFileIsIdentified_whenFileIsRenamedInPatchSets() throws Exception {
String renamedFilePath = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, renamedFilePath);
gApi.changes().id(changeId).edit().publish();
@@ -2247,7 +2239,7 @@
}
@Test
- public void renamedFileWithOnlyRebaseHunksIsIdentified_WhenRenamedBetweenPatchSets()
+ public void renamedFileWithOnlyRebaseHunksIsIdentified_whenRenamedBetweenPatchSets()
throws Exception {
String newFilePath1 = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, newFilePath1);
@@ -2282,7 +2274,7 @@
}
@Test
- public void renamedFileWithOnlyRebaseHunksIsIdentified_WhenRenamedForRebaseAndForPatchSets()
+ public void renamedFileWithOnlyRebaseHunksIsIdentified_whenRenamedForRebaseAndForPatchSets()
throws Exception {
String newFilePath1 = "renamed_some_file.txt";
gApi.changes().id(changeId).edit().renameFile(FILE_NAME, newFilePath1);
@@ -2837,7 +2829,7 @@
}
@Test
- public void symlinkConvertedToRegularFileIsIdentifiedAsRewritten() throws Exception {
+ public void addDeleteByJgit_isIdentifiedAsRewritten() throws Exception {
String target = "file.txt";
String symlink = "link.lnk";
@@ -2846,58 +2838,70 @@
pushFactory
.create(admin.newIdent(), testRepo, "Commit Subject", target, "content")
.addSymlink(symlink, target);
-
PushOneCommit.Result result = push.to("refs/for/master");
String initialRev = gApi.changes().id(result.getChangeId()).get().currentRevision;
+ String cId = result.getChangeId();
- // Delete the symlink with patchset 2
- gApi.changes().id(result.getChangeId()).edit().deleteFile(symlink);
- gApi.changes().id(result.getChangeId()).edit().publish();
+ // Delete the symlink with PS2
+ gApi.changes().id(cId).edit().deleteFile(symlink);
+ gApi.changes().id(cId).edit().publish();
- // Re-add the symlink as a regular file with patchset 3
- gApi.changes()
- .id(result.getChangeId())
- .edit()
- .modifyFile(symlink, RawInputUtil.create("Content of the new file named 'symlink'"));
- gApi.changes().id(result.getChangeId()).edit().publish();
+ // Re-add the symlink as a regular file with PS3
+ gApi.changes().id(cId).edit().modifyFile(symlink, RawInputUtil.create("new content"));
+ gApi.changes().id(cId).edit().publish();
- Map<String, FileInfo> changedFiles =
- gApi.changes().id(result.getChangeId()).current().files(initialRev);
-
+ // Changed files: JGit returns two {DELETED/ADDED} entries for the file.
+ // The diff logic combines both into a single REWRITTEN entry.
+ Map<String, FileInfo> changedFiles = gApi.changes().id(cId).current().files(initialRev);
assertThat(changedFiles.keySet()).containsExactly("/COMMIT_MSG", symlink);
-
- // Both old and new diff caches agree that the state is rewritten
assertThat(changedFiles.get(symlink).status).isEqualTo('W'); // Rewritten
- DiffInfo diffInfo =
- gApi.changes().id(result.getChangeId()).current().file(symlink).diff(initialRev);
+ // Detailed diff: Old diff cache returns ADDED entry. New Diff Cache returns REWRITE.
+ DiffInfo diffInfo = gApi.changes().id(cId).current().file(symlink).diff(initialRev);
+ assertThat(diffInfo.content).hasSize(1);
+ assertThat(diffInfo).content().element(0).linesOfB().containsExactly("new content");
+ assertThat(diffInfo.changeType).isEqualTo(ChangeType.REWRITE);
+ }
- // TODO(ghareeb): Remove the else branch when the new diff cache is rolled out as default.
- if (useNewDiffCacheGetDiff) {
- // File diff in New diff cache: change type is correctly identified as REWRITTEN
- assertThat(diffInfo.changeType).isEqualTo(ChangeType.REWRITE);
- assertThat(diffInfo.content).hasSize(2);
- assertThat(diffInfo)
- .content()
- .element(0)
- .linesOfB()
- .containsExactly("Content of the new file named 'symlink'");
- assertThat(diffInfo).content().element(1).linesOfA().containsExactly("file.txt");
- } else {
- // File diff in old diff cache: The diff logic identifies two entries for the file:
- // 1. One entry as 'DELETED' for the symlink.
- // 2. Another entry as 'ADDED' for the new regular file.
- // Since the diff logic returns a single entry, the implementation prioritizes the 'ADDED'
- // entry in this case so that the user is able to see the new content that was added to the
- // file.
- assertThat(diffInfo.changeType).isEqualTo(ChangeType.ADDED);
- assertThat(diffInfo.content).hasSize(1);
- assertThat(diffInfo)
- .content()
- .element(0)
- .linesOfB()
- .containsExactly("Content of the new file named 'symlink'");
- }
+ @Test
+ public void renameDeleteByJgit_isIdentifiedAsRewritten() throws Exception {
+ String target = "file.txt";
+ String symlink = "link.lnk";
+ PushOneCommit push =
+ pushFactory
+ .create(admin.newIdent(), testRepo, "Commit Subject", target, "content")
+ .addSymlink(symlink, target);
+ PushOneCommit.Result result = push.to("refs/for/master");
+ String cId = result.getChangeId();
+ String initialRev = gApi.changes().id(cId).get().currentRevision;
+
+ // Delete both symlink and target with PS2
+ gApi.changes().id(cId).edit().deleteFile(symlink);
+ gApi.changes().id(cId).edit().deleteFile(target);
+ gApi.changes().id(cId).edit().publish();
+
+ // Re-create the symlink as a regular file with PS3
+ gApi.changes().id(cId).edit().modifyFile(symlink, RawInputUtil.create("content"));
+ gApi.changes().id(cId).edit().publish();
+
+ // Changed files: JGit returns two {DELETED/RENAMED} entries for the file.
+ // The diff logic combines both into a single REWRITTEN entry.
+ Map<String, FileInfo> changedFiles = gApi.changes().id(cId).current().files(initialRev);
+ assertThat(changedFiles.keySet()).containsExactly("/COMMIT_MSG", symlink);
+ assertThat(changedFiles.get(symlink).status).isEqualTo('W'); // Rewritten
+
+ // Detailed diff: Old diff cache returns RENAMED entry. New Diff Cache returns REWRITE.
+ DiffInfo diffInfo = gApi.changes().id(cId).current().file(symlink).diff(initialRev);
+ assertThat(diffInfo)
+ .diffHeader()
+ .containsExactly(
+ "diff --git a/file.txt b/link.lnk",
+ "similarity index 100%",
+ "rename from file.txt",
+ "rename to link.lnk");
+ assertThat(diffInfo.content).hasSize(1);
+ assertThat(diffInfo).content().element(0).commonLines().containsExactly("content");
+ assertThat(diffInfo.changeType).isEqualTo(ChangeType.REWRITE);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 3d2026b..d3fe83f 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -47,6 +47,7 @@
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.TestProjectInput;
+import com.google.gerrit.acceptance.UseClockStep;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
@@ -1199,6 +1200,7 @@
}
@Test
+ @UseClockStep
public void cherryPickSetsReadyChangeOnNewPatchset() throws Exception {
PushOneCommit.Result result = pushTo("refs/for/master");
CherryPickInput input = new CherryPickInput();
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java
deleted file mode 100644
index 46954e98..0000000
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheForSingleFileIT.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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, enabled for the single file "Get
- * Diff" endpoint. This is temporary until the new diff cache is fully deployed. The new diff cache
- * will become the default in the future.
- */
-public class RevisionNewDiffCacheForSingleFileIT extends RevisionDiffIT {
- @ConfigSuite.Default
- public static Config newDiffCacheConfig() {
- Config config = new Config();
- config.setBoolean("cache", "diff_cache", "runNewDiffCache_GetDiff", true);
- return config;
- }
-}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
deleted file mode 100644
index 714bd78..0000000
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionNewDiffCacheIT.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.server.change.FileInfoJsonExperimentImpl;
-import com.google.gerrit.testing.ConfigSuite;
-import org.eclipse.jgit.lib.Config;
-
-/**
- * Runs the {@link RevisionDiffIT} with the list files endpoint using 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.setString(
- "experiments", null, "enabled", FileInfoJsonExperimentImpl.NEW_DIFF_CACHE_FEATURE);
- return config;
- }
-}
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
index 85a7b29..875ce97 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RobotCommentsIT.java
@@ -156,15 +156,15 @@
@UseClockStep
@Test
public void addedRobotCommentsAreLinkedToChangeMessages() throws Exception {
- TestTimeUtil.resetWithClockStep(0, TimeUnit.SECONDS);
- createChange();
- /* Advancing the time after creating the change so that the first robot comment is not in the same timestamp as with the change creation */
+ // Advancing the time after creating the change so that the first robot comment is not in the
+ // same timestamp as with the change creation.
TestTimeUtil.incrementClock(10, TimeUnit.SECONDS);
RobotCommentInput c1 = TestCommentHelper.createRobotCommentInput(FILE_NAME);
RobotCommentInput c2 = TestCommentHelper.createRobotCommentInput(FILE_NAME);
RobotCommentInput c3 = TestCommentHelper.createRobotCommentInput(FILE_NAME);
- /* Give the robot comments identifiable names for testing */
+
+ // Give the robot comments identifiable names for testing
c1.message = "robot comment 1";
c2.message = "robot comment 2";
c3.message = "robot comment 3";
diff --git a/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java b/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
index a90cd56..0e0168e 100644
--- a/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
+++ b/javatests/com/google/gerrit/acceptance/edit/ChangeEditIT.java
@@ -281,7 +281,7 @@
}
@Test
- public void rebaseEditWithConflictsRest_Conflict() throws Exception {
+ public void rebaseEditWithConflictsRest_conflict() throws Exception {
PatchSet currentPatchSet = getCurrentPatchSet(changeId2);
createEmptyEditFor(changeId2);
gApi.changes().id(changeId2).edit().modifyFile(FILE_NAME, RawInputUtil.create(CONTENT_NEW));
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractForcePush.java b/javatests/com/google/gerrit/acceptance/git/AbstractForcePush.java
index 88d0937..f4918b6 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractForcePush.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractForcePush.java
@@ -21,6 +21,7 @@
import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.OK;
import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
+import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
@@ -34,7 +35,7 @@
import org.junit.Test;
public abstract class AbstractForcePush extends AbstractDaemonTest {
- @Inject private ProjectOperations projectOperations;
+ @Inject protected ProjectOperations projectOperations;
@Test
public void forcePushNotAllowed() throws Exception {
@@ -116,6 +117,28 @@
assertDeleteRef(OK);
}
+ @Test
+ public void directPushSendsEmail() throws Exception {
+ // create a change
+ PushOneCommit push1 =
+ pushFactory.create(admin.newIdent(), testRepo, "change1", "a.txt", "content");
+ PushOneCommit.Result r = push1.to("refs/for/master");
+ r.assertOkStatus();
+
+ // Add reviewer to receive notifications
+ gApi.changes().id(r.getChangeId()).addReviewer(user.email());
+ sender.clear();
+
+ // direct submit the change
+ PushOneCommit.Result r1 = push1.to("refs/heads/master");
+ r1.assertOkStatus();
+
+ // email received
+ assertThat(sender.getMessages()).hasSize(1);
+ assertThat(Iterables.getOnlyElement(sender.getMessages()).body())
+ .contains("has submitted this change");
+ }
+
private void assertDeleteRef(RemoteRefUpdate.Status expectedStatus) throws Exception {
BranchInput in = new BranchInput();
in.ref = "refs/heads/test";
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index 5cf0403..2253202 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -1266,13 +1266,13 @@
}
@Test
- public void pushForMasterWithApprovals_MissingLabel() throws Exception {
+ public void pushForMasterWithApprovals_missingLabel() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master%l=Verify");
r.assertErrorStatus("label \"Verify\" is not a configured label");
}
@Test
- public void pushForMasterWithApprovals_ValueOutOfRange() throws Exception {
+ public void pushForMasterWithApprovals_valueOutOfRange() throws Exception {
PushOneCommit.Result r = pushTo("refs/for/master%l=Code-Review-3");
r.assertErrorStatus("label \"Code-Review\": -3 is not a valid value");
}
diff --git a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
index 92770ba..194f5f9 100644
--- a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
@@ -1434,7 +1434,6 @@
* Assert that refs seen by a non-admin user match the expected refs.
*
* @param expectedRefs expected refs.
- * @throws Exception
*/
private void assertUploadPackRefs(String... expectedRefs) throws Exception {
assertRefs(project, user, true, expectedRefs);
diff --git a/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java b/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java
new file mode 100644
index 0000000..83df896
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/pgm/ChangeExternalIdCaseSensitivityIT.java
@@ -0,0 +1,239 @@
+// 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.pgm;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_EXTERNAL;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
+
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.StandaloneSiteTest;
+import com.google.gerrit.entities.Account;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
+import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdNotes;
+import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
+import org.junit.After;
+import org.junit.Test;
+
+@NoHttpd
+public class ChangeExternalIdCaseSensitivityIT extends StandaloneSiteTest {
+
+ private static final boolean CASE_SENSITIVE = false;
+ private static final boolean CASE_INSENSITIVE = true;
+
+ private ServerContext ctx;
+ private ExternalIdNotes extIdNotes;
+ private ExternalIdFactory extIdFactory;
+ private MetaDataUpdate md;
+ private FileBasedConfig config;
+
+ @After
+ public void cleanup() throws Exception {
+ if (ctx != null) {
+ ctx.close();
+ }
+ }
+
+ @Test
+ public void externalIdNoteNameIsMigratedToCaseInsensitive() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+
+ ctx.close();
+ runChangeExternalIdCaseSensitivity();
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_INSENSITIVE);
+ }
+
+ @Test
+ public void externalIdNoteNameIsMigratedToCaseSensitive() throws Exception {
+ prepareExternalIdNotes(CASE_INSENSITIVE);
+
+ ctx.close();
+ runChangeExternalIdCaseSensitivity();
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_SENSITIVE);
+ }
+
+ @Test
+ public void migrationFailsWithDuplicates() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "JohnDoe", Account.id(1)));
+ extIdNotes.commit(md);
+
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:johndoe", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:JohnDoe", false)).isPresent())
+ .isTrue();
+
+ ctx.close();
+ assertThrows(DuplicateExternalIdKeyException.class, () -> runChangeExternalIdCaseSensitivity());
+ ctx = startServer();
+ extIdNotes = getExternalIdNotes(ctx);
+
+ assertExternalIdNotes(CASE_SENSITIVE);
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:johndoe", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("username:JohnDoe", false)).isPresent())
+ .isTrue();
+ }
+
+ @Test
+ public void userNameCaseInsensitiveOptionIsSwitched() throws Exception {
+ configureUserNameCaseInsensitive(CASE_SENSITIVE);
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ runChangeExternalIdCaseSensitivity();
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isTrue();
+ runChangeExternalIdCaseSensitivity();
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ }
+
+ @Test
+ public void dryrunDoesNotPersistChanges() throws Exception {
+ prepareExternalIdNotes(CASE_SENSITIVE);
+ ctx.close();
+ runGerrit("ChangeExternalIdCaseSensitivity", "-d", sitePaths.site_path.toString(), "--dryrun");
+
+ config.load();
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+
+ ctx = startServer();
+ assertExternalIdNotes(CASE_SENSITIVE);
+ }
+
+ private void prepareExternalIdNotes(boolean userNameCaseInsensitive) throws Exception {
+ configureUserNameCaseInsensitive(userNameCaseInsensitive);
+ initSite();
+ ctx = startServer();
+ extIdFactory = ctx.getInjector().getInstance(ExternalIdFactory.class);
+ Project.NameKey allUsers = ctx.getInjector().getInstance(AllUsersName.class);
+ extIdNotes = getExternalIdNotes(ctx, allUsers);
+ md = getMetaDataUpdate(ctx, allUsers);
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "johndoe", Account.id(0)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GERRIT, "johndoe", Account.id(0)));
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_USERNAME, "JaneDoe", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GERRIT, "JaneDoe", Account.id(1)));
+
+ extIdNotes.insert(extIdFactory.create(SCHEME_MAILTO, "Jane@Doe.com", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_UUID, "Abc123", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_GPGKEY, "Abc123", Account.id(1)));
+ extIdNotes.insert(extIdFactory.create(SCHEME_EXTERNAL, "saml/JaneDoe", Account.id(1)));
+ extIdNotes.commit(md);
+
+ assertExternalIdNotes(userNameCaseInsensitive);
+ }
+
+ private void assertExternalIdNotes(boolean userNameCaseInsensitive) throws Exception {
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:johndoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:JaneDoe", !userNameCaseInsensitive))
+ .isPresent())
+ .isFalse();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("username:JaneDoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:johndoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:JaneDoe", !userNameCaseInsensitive))
+ .isPresent())
+ .isFalse();
+ assertThat(
+ extIdNotes
+ .get(ExternalId.Key.parse("gerrit:JaneDoe", userNameCaseInsensitive))
+ .isPresent())
+ .isTrue();
+
+ assertThat(extIdNotes.get(ExternalId.Key.parse("mailto:Jane@Doe.com", false)).isPresent())
+ .isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("uuid:Abc123", false)).isPresent()).isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("gpgkey:Abc123", false)).isPresent()).isTrue();
+ assertThat(extIdNotes.get(ExternalId.Key.parse("external:saml/JaneDoe", false)).isPresent())
+ .isTrue();
+ }
+
+ private void configureUserNameCaseInsensitive(boolean userNameCaseInsensitive)
+ throws IOException, ConfigInvalidException {
+ config = new FileBasedConfig(baseConfig, sitePaths.gerrit_config.toFile(), FS.DETECTED);
+ config.load();
+ config.setBoolean("auth", null, "userNameCaseInsensitive", userNameCaseInsensitive);
+ config.save();
+ if (userNameCaseInsensitive) {
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isTrue();
+ } else {
+ assertThat(config.getBoolean("auth", "userNameCaseInsensitive", false)).isFalse();
+ }
+ }
+
+ private void initSite() throws Exception {
+ runGerrit("init", "-d", sitePaths.site_path.toString(), "--show-stack-trace");
+ }
+
+ private void runChangeExternalIdCaseSensitivity() throws Exception {
+ runGerrit("ChangeExternalIdCaseSensitivity", "-d", sitePaths.site_path.toString(), "--batch");
+ }
+
+ private static ExternalIdNotes getExternalIdNotes(ServerContext ctx) throws Exception {
+ return getExternalIdNotes(ctx, ctx.getInjector().getInstance(AllUsersName.class));
+ }
+
+ private static ExternalIdNotes getExternalIdNotes(ServerContext ctx, Project.NameKey allUsers)
+ throws Exception {
+ GitRepositoryManager repoManager = ctx.getInjector().getInstance(GitRepositoryManager.class);
+ ExternalIdNotes.FactoryNoReindex extIdNotesFactory =
+ ctx.getInjector().getInstance(ExternalIdNotes.FactoryNoReindex.class);
+ return extIdNotesFactory.load(repoManager.openRepository(allUsers));
+ }
+
+ private static MetaDataUpdate getMetaDataUpdate(ServerContext ctx, Project.NameKey allUsers)
+ throws Exception {
+ MetaDataUpdate.Server metaDataUpdateFactory =
+ ctx.getInjector().getInstance(MetaDataUpdate.Server.class);
+ return metaDataUpdateFactory.create(allUsers);
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/rest/CancellationIT.java b/javatests/com/google/gerrit/acceptance/rest/CancellationIT.java
index 1a96d82..ed5e559 100644
--- a/javatests/com/google/gerrit/acceptance/rest/CancellationIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/CancellationIT.java
@@ -28,7 +28,6 @@
import com.google.gerrit.server.cancellation.RequestCancelledException;
import com.google.gerrit.server.cancellation.RequestStateProvider;
import com.google.gerrit.server.events.CommitReceivedEvent;
-import com.google.gerrit.server.experiments.ExperimentFeaturesConstants;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidationListener;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
@@ -153,7 +152,7 @@
"/projects/" + name("new"), new BasicHeader(RestApiServlet.X_GERRIT_DEADLINE, "1ms"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
assertThat(response.getEntityContent())
- .isEqualTo("Client Provided Deadline Exceeded\n\ntimeout=1ms");
+ .isEqualTo("Client Provided Deadline Exceeded\n\nclient.timeout=1ms");
}
@Test
@@ -206,7 +205,8 @@
public void stricterDeadlineTakesPrecedence() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=1ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\nfoo.timeout=1ms");
}
@Test
@@ -215,7 +215,8 @@
public void abortIfServerDeadlineExceeded_requestType() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=1ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
}
@Test
@@ -224,7 +225,34 @@
public void abortIfServerDeadlineExceeded_requestUriPattern() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=1ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
+ }
+
+ @Test
+ @GerritConfig(name = "deadline.default.timeout", value = "1ms")
+ @GerritConfig(
+ name = "deadline.default.excludedRequestUriPattern",
+ value = "/projects/non-matching")
+ public void abortIfServerDeadlineExceeded_excludedRequestUriPattern() throws Exception {
+ RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
+ }
+
+ @Test
+ @GerritConfig(name = "deadline.default.timeout", value = "1ms")
+ @GerritConfig(name = "deadline.default.requestUriPattern", value = "/projects/.*")
+ @GerritConfig(
+ name = "deadline.default.excludedRequestUriPattern",
+ value = "/projects/non-matching")
+ public void abortIfServerDeadlineExceeded_requestUriPatternAndExcludedRequestUriPattern()
+ throws Exception {
+ RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
+ assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
}
@Test
@@ -233,7 +261,8 @@
public void abortIfServerDeadlineExceeded_projectPattern() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=1ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
}
@Test
@@ -242,7 +271,8 @@
public void abortIfServerDeadlineExceeded_account() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=1ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=1ms");
}
@Test
@@ -263,6 +293,24 @@
@Test
@GerritConfig(name = "deadline.default.timeout", value = "1ms")
+ @GerritConfig(name = "deadline.default.excludedRequestUriPattern", value = "/projects/.*")
+ public void nonMatchingServerDeadlineIsIgnored_excludedRequestUriPattern() throws Exception {
+ RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
+ response.assertCreated();
+ }
+
+ @Test
+ @GerritConfig(name = "deadline.default.timeout", value = "1ms")
+ @GerritConfig(name = "deadline.default.requestUriPattern", value = "/projects/.*")
+ @GerritConfig(name = "deadline.default.excludedRequestUriPattern", value = "/projects/.*new")
+ public void nonMatchingServerDeadlineIsIgnored_requestUriPatternAndExcludedRequestUriPattern()
+ throws Exception {
+ RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
+ response.assertCreated();
+ }
+
+ @Test
+ @GerritConfig(name = "deadline.default.timeout", value = "1ms")
@GerritConfig(name = "deadline.default.projectPattern", value = ".*foo.*")
public void nonMatchingServerDeadlineIsIgnored_projectPattern() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
@@ -292,7 +340,8 @@
public void nonAdvisoryDeadlineIsAppliedIfStricterAdvisoryDeadlineExists() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
- assertThat(response.getEntityContent()).isEqualTo("Server Deadline Exceeded\n\ntimeout=2ms");
+ assertThat(response.getEntityContent())
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=2ms");
}
@Test
@@ -334,6 +383,14 @@
@Test
@GerritConfig(name = "deadline.default.timeout", value = "1ms")
+ @GerritConfig(name = "deadline.default.excludedRequestUriPattern", value = "][")
+ public void invalidServerDeadlineIsIgnored_invalidExcludedRequestUriPattern() throws Exception {
+ RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
+ response.assertCreated();
+ }
+
+ @Test
+ @GerritConfig(name = "deadline.default.timeout", value = "1ms")
@GerritConfig(name = "deadline.default.projectPattern", value = "][")
public void invalidServerDeadlineIsIgnored_invalidProjectPattern() throws Exception {
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
@@ -373,7 +430,7 @@
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
- throw new RuntimeException("interrupted during sleep");
+ throw new RuntimeException("interrupted during sleep", e);
}
}
};
@@ -382,7 +439,7 @@
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
assertThat(response.getEntityContent())
- .isEqualTo("Server Deadline Exceeded\n\ntimeout=500ms");
+ .isEqualTo("Server Deadline Exceeded\n\ndefault.timeout=500ms");
}
// verify that the exceeded deadline for the previous request, isn't applied to a new request
RestResponse response = adminRestSession.putWithHeaders("/projects/" + name("new2"));
@@ -397,7 +454,7 @@
"/projects/" + name("new"), new BasicHeader(RestApiServlet.X_GERRIT_DEADLINE, "2ms"));
assertThat(response.getStatusCode()).isEqualTo(SC_REQUEST_TIMEOUT);
assertThat(response.getEntityContent())
- .isEqualTo("Client Provided Deadline Exceeded\n\ntimeout=2ms");
+ .isEqualTo("Client Provided Deadline Exceeded\n\nclient.timeout=2ms");
}
@Test
@@ -519,38 +576,24 @@
public void abortPushIfServerDeadlineExceeded() throws Exception {
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Server Deadline Exceeded (timeout=1ms)");
+ r.assertErrorStatus("Server Deadline Exceeded (default.timeout=1ms)");
}
@Test
@GerritConfig(name = "receive.timeout", value = "1ms")
- @GerritConfig(
- name = "experiments.enabled",
- value = ExperimentFeaturesConstants.GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_PUSH_CANCELLATION)
public void abortPushIfTimeoutExceeded() throws Exception {
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Server Deadline Exceeded (timeout=1ms)");
- }
-
- @Test
- @GerritConfig(name = "receive.timeout", value = "1ms")
- public void pushNotAbortedIfTimeoutExceededAndExperimentNotEnabled() throws Exception {
- PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
- PushOneCommit.Result r = push.to("refs/for/master");
- r.assertOkStatus();
+ r.assertErrorStatus("Server Deadline Exceeded (receive.timeout=1ms)");
}
@Test
@GerritConfig(name = "receive.timeout", value = "1ms")
@GerritConfig(name = "deadline.default.timeout", value = "10s")
- @GerritConfig(
- name = "experiments.enabled",
- value = ExperimentFeaturesConstants.GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_PUSH_CANCELLATION)
public void receiveTimeoutTakesPrecedence() throws Exception {
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Server Deadline Exceeded (timeout=1ms)");
+ r.assertErrorStatus("Server Deadline Exceeded (receive.timeout=1ms)");
}
@Test
@@ -560,7 +603,7 @@
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
push.setPushOptions(pushOptions);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Client Provided Deadline Exceeded (timeout=1ms)");
+ r.assertErrorStatus("Client Provided Deadline Exceeded (client.timeout=1ms)");
}
@Test
@@ -611,21 +654,18 @@
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
push.setPushOptions(pushOptions);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Client Provided Deadline Exceeded (timeout=2ms)");
+ r.assertErrorStatus("Client Provided Deadline Exceeded (client.timeout=2ms)");
}
@Test
@GerritConfig(name = "receive.timeout", value = "1ms")
- @GerritConfig(
- name = "experiments.enabled",
- value = ExperimentFeaturesConstants.GERRIT_BACKEND_REQUEST_FEATURE_ENABLE_PUSH_CANCELLATION)
public void clientProvidedDeadlineOnPushDoesntOverrideServerTimeout() throws Exception {
List<String> pushOptions = new ArrayList<>();
pushOptions.add("deadline=10m");
PushOneCommit push = pushFactory.create(admin.newIdent(), testRepo);
push.setPushOptions(pushOptions);
PushOneCommit.Result r = push.to("refs/for/master");
- r.assertErrorStatus("Server Deadline Exceeded (timeout=1ms)");
+ r.assertErrorStatus("Server Deadline Exceeded (receive.timeout=1ms)");
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/rest/RestApiServletIT.java b/javatests/com/google/gerrit/acceptance/rest/RestApiServletIT.java
index 219ef12..4efdbba 100644
--- a/javatests/com/google/gerrit/acceptance/rest/RestApiServletIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/RestApiServletIT.java
@@ -30,6 +30,7 @@
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.restapi.Url;
+import com.google.gerrit.httpd.restapi.ParameterParser;
import com.google.gerrit.httpd.restapi.RestApiServlet;
import com.google.inject.Inject;
import java.io.IOException;
@@ -83,6 +84,11 @@
}
@Test
+ public void experimentRequestParamIsReserved() throws Exception {
+ assertRestResponseWithParameters(SC_OK, ParameterParser.EXPERIMENT_PARAMETER, "exp1");
+ }
+
+ @Test
public void xGerritUpdatedRefNotSetByDefault() throws Exception {
Result change = createChange();
String origin = adminRestSession.url();
@@ -415,6 +421,15 @@
return change.getChange().notes().getRevision();
}
+ private RestResponse assertRestResponseWithParameters(int status, String k, String v)
+ throws Exception {
+ RestResponse response =
+ adminRestSession.getWithHeaders(ANY_REST_API + "?" + k + "=" + v, ACCEPT_STAR_HEADER);
+ assertThat(response.getStatusCode()).isEqualTo(status);
+
+ return response;
+ }
+
private RestResponse prettyJsonRestResponse(String ppArgument, int ppValue) throws Exception {
RestResponse response =
adminRestSession.getWithHeaders(
diff --git a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
index 530f2ec..7e40b2b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/TraceIT.java
@@ -711,6 +711,94 @@
}
@Test
+ @GerritConfig(name = "tracing.issue123.excludedRequestUriPattern", value = "/projects/.*")
+ public void traceExcludedRequestUriPattern() throws Exception {
+ TraceValidatingProjectCreationValidationListener projectCreationListener =
+ new TraceValidatingProjectCreationValidationListener();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectCreationListener)) {
+ RestResponse response = adminRestSession.put("/projects/xyz1");
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(projectCreationListener.traceId).isNull();
+ assertThat(projectCreationListener.isLoggingForced).isFalse();
+
+ // The logging tag with the project name is also set if tracing is off.
+ assertThat(projectCreationListener.tags.get("project")).containsExactly("xyz1");
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "tracing.issue123.excludedRequestUriPattern", value = "/projects/no-match")
+ public void traceExcludedRequestUriPatternNoMatch() throws Exception {
+ TraceValidatingProjectCreationValidationListener projectCreationListener =
+ new TraceValidatingProjectCreationValidationListener();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectCreationListener)) {
+ RestResponse response = adminRestSession.put("/projects/xyz3");
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(projectCreationListener.traceId).isEqualTo("issue123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+ assertThat(projectCreationListener.tags.get("project")).containsExactly("xyz3");
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "tracing.issue123.requestUriPattern", value = "/projects/.*")
+ @GerritConfig(name = "tracing.issue123.excludedRequestUriPattern", value = "/projects/xyz2")
+ public void traceRequestUriPatternAndExcludedRequestUriPattern() throws Exception {
+ TraceValidatingProjectCreationValidationListener projectCreationListener =
+ new TraceValidatingProjectCreationValidationListener();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectCreationListener)) {
+ RestResponse response = adminRestSession.put("/projects/xyz2");
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(projectCreationListener.traceId).isNull();
+ assertThat(projectCreationListener.isLoggingForced).isFalse();
+
+ // The logging tag with the project name is also set if tracing is off.
+ assertThat(projectCreationListener.tags.get("project")).containsExactly("xyz2");
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "tracing.issue123.requestUriPattern", value = "/projects/.*")
+ @GerritConfig(name = "tracing.issue123.excludedRequestUriPattern", value = "/projects/no-match")
+ public void traceRequestUriPatternAndExcludedRequestUriPatternNoMatch() throws Exception {
+ TraceValidatingProjectCreationValidationListener projectCreationListener =
+ new TraceValidatingProjectCreationValidationListener();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectCreationListener)) {
+ RestResponse response = adminRestSession.put("/projects/xyz3");
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(projectCreationListener.traceId).isEqualTo("issue123");
+ assertThat(projectCreationListener.isLoggingForced).isTrue();
+ assertThat(projectCreationListener.tags.get("project")).containsExactly("xyz3");
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "tracing.issue123.excludedRequestUriPattern", value = "][")
+ public void traceExcludedRequestUriInvalidRegEx() throws Exception {
+ TraceValidatingProjectCreationValidationListener projectCreationListener =
+ new TraceValidatingProjectCreationValidationListener();
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(projectCreationListener)) {
+ RestResponse response = adminRestSession.put("/projects/xyz4");
+ assertThat(response.getStatusCode()).isEqualTo(SC_CREATED);
+ assertThat(response.getHeader(RestApiServlet.X_GERRIT_TRACE)).isNull();
+ assertThat(projectCreationListener.traceId).isNull();
+ assertThat(projectCreationListener.isLoggingForced).isFalse();
+
+ // The logging tag with the project name is also set if tracing is off.
+ assertThat(projectCreationListener.tags.get("project")).containsExactly("xyz4");
+ }
+ }
+
+ @Test
@GerritConfig(name = "retry.retryWithTraceOnFailure", value = "true")
public void noAutoRetryIfExceptionCausesNormalRetrying() throws Exception {
String changeId = createChange().getChangeId();
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/AccountAssert.java b/javatests/com/google/gerrit/acceptance/rest/account/AccountAssert.java
index 0b0f2ec..79e8ab0 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/AccountAssert.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/AccountAssert.java
@@ -14,7 +14,6 @@
package com.google.gerrit.acceptance.rest.account;
-import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.Iterables;
@@ -39,8 +38,7 @@
if (testAccount.tags().isEmpty()) {
assertThat(accountInfo.tags).isNull();
} else {
- assertThat(accountInfo.tags.stream().map(Enum::name).collect(toImmutableList()))
- .containsExactlyElementsIn(testAccount.tags());
+ assertThat(accountInfo.tags).containsExactlyElementsIn(testAccount.tags());
}
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java b/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
index 8feac20..d055875 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/EmailIT.java
@@ -40,6 +40,8 @@
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.account.Realm;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AuthConfig;
@@ -63,6 +65,8 @@
@Inject private ExternalIds externalIds;
@Inject private Provider<Emails> emails;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdFactory externalIdFactory;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Test
public void addEmail() throws Exception {
@@ -138,7 +142,7 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(
+ externalIdFactory.createWithEmail(
ExternalId.SCHEME_EXTERNAL, "foo", admin.id(), email)));
assertThat(gApi.accounts().self().get().email).isNotEqualTo(email);
@@ -182,7 +186,7 @@
public void setPreferredEmailToEmailFromCustomRealmThatDoesntExistAsExternalId()
throws Exception {
String email = "foo@example.com";
- ExternalId.Key mailtoExtIdKey = ExternalId.Key.create(ExternalId.SCHEME_MAILTO, email);
+ ExternalId.Key mailtoExtIdKey = externalIdKeyFactory.create(ExternalId.SCHEME_MAILTO, email);
assertThat(externalIds.get(mailtoExtIdKey)).isEmpty();
assertThat(gApi.accounts().self().get().email).isNotEqualTo(email);
@@ -200,7 +204,7 @@
@Test
public void setPreferredEmailToEmailFromCustomRealmThatBelongsToOtherAccount() throws Exception {
- ExternalId mailToExtId = ExternalId.createEmail(user.id(), user.email());
+ ExternalId mailToExtId = externalIdFactory.createEmail(user.id(), user.email());
assertThat(externalIds.get(mailToExtId.key())).isPresent();
Context oldCtx =
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
index 20b378b..cd123aa 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/ExternalIdIT.java
@@ -21,6 +21,8 @@
import static com.google.gerrit.acceptance.GitUtil.pushHead;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GERRIT;
+import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_GPGKEY;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_MAILTO;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_UUID;
@@ -37,6 +39,8 @@
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.common.data.GlobalCapability;
@@ -53,7 +57,10 @@
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
+import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdReader;
import com.google.gerrit.server.account.externalids.ExternalIds;
@@ -92,6 +99,8 @@
@Inject private ExternalIdNotes.Factory externalIdNotesFactory;
@Inject private ProjectOperations projectOperations;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+ @Inject private ExternalIdFactory externalIdFactory;
@ConfigSuite.Default
public static Config partialCacheReloadingEnabled() {
@@ -194,7 +203,7 @@
}
@Test
- public void deleteExternalIdOfOtherUserUnderOwnAccount_UnprocessableEntity() throws Exception {
+ public void deleteExternalIdOfOtherUserUnderOwnAccount_unprocessableEntity() throws Exception {
List<AccountExternalIdInfo> extIds = gApi.accounts().self().getExternalIds();
requestScopeOperations.setApiUser(user.id());
UnprocessableEntityException thrown =
@@ -249,19 +258,60 @@
gApi.accounts()
.self()
.deleteExternalIds(
- ImmutableList.of(ExternalId.Key.create(SCHEME_MAILTO, preferredEmail).get()));
+ ImmutableList.of(externalIdKeyFactory.create(SCHEME_MAILTO, preferredEmail).get()));
assertThat(gApi.accounts().self().get().email).isNull();
}
@Test
- public void deleteExternalIds_Conflict() throws Exception {
+ public void deleteExternalIdOfUsernameByNonAdminForbidden() throws Exception {
List<String> toDelete = new ArrayList<>();
String externalIdStr = "username:" + user.username();
toDelete.add(externalIdStr);
- RestResponse response = userRestSession.post("/accounts/self/external.ids:delete", toDelete);
- response.assertConflict();
- assertThat(response.getEntityContent())
- .isEqualTo(String.format("External id %s cannot be deleted", externalIdStr));
+ RestResponse response =
+ userRestSession.post("/accounts/" + admin.id() + "/external.ids:delete", toDelete);
+ response.assertForbidden();
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameSelfForbidden() throws Exception {
+ List<String> toDelete = new ArrayList<>();
+ String externalIdStr = "username:" + admin.username();
+ toDelete.add(externalIdStr);
+ RestResponse response = adminRestSession.post("/accounts/self/external.ids:delete", toDelete);
+ response.assertForbidden();
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameByAdmin() throws Exception {
+ List<String> toDelete = new ArrayList<>();
+ String externalIdStr = "username:" + user.username();
+ toDelete.add(externalIdStr);
+ RestResponse response =
+ adminRestSession.post("/accounts/" + user.id() + "/external.ids:delete", toDelete);
+ response.assertNoContent();
+ List<AccountExternalIdInfo> results = gApi.accounts().id(user.id().get()).getExternalIds();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).identity).isEqualTo("mailto:user1@example.com");
+ }
+
+ @Test
+ public void deleteExternalIdOfUsernameMaintainServer() throws Exception {
+ projectOperations
+ .allProjectsForUpdate()
+ .add(allowCapability(GlobalCapability.MAINTAIN_SERVER).group(REGISTERED_USERS))
+ .add(allowCapability(GlobalCapability.MODIFY_ACCOUNT).group(REGISTERED_USERS))
+ .update();
+
+ List<String> toDelete = new ArrayList<>();
+ TestAccount user2 = accountCreator.user2();
+ String externalIdStr = "username:" + user2.username();
+ toDelete.add(externalIdStr);
+ RestResponse response =
+ userRestSession.post("/accounts/" + user2.id() + "/external.ids:delete", toDelete);
+ response.assertNoContent();
+ List<AccountExternalIdInfo> results = gApi.accounts().id(user2.id().get()).getExternalIds();
+ assertThat(results).hasSize(1);
+ assertThat(results.get(0).identity).isEqualTo("mailto:user2@example.com");
}
@Test
@@ -525,12 +575,12 @@
// create valid external IDs
insertExtId(
- ExternalId.createWithPassword(
- ExternalId.Key.parse(nextId(scheme, i)),
+ externalIdFactory.createWithPassword(
+ externalIdKeyFactory.parse(nextId(scheme, i)),
admin.id(),
"admin.other@example.com",
"secret-password"));
- insertExtId(ExternalId.createEmail(admin.id(), "admin.other@example.com"));
+ insertExtId(externalIdFactory.createEmail(admin.id(), "admin.other@example.com"));
insertExtId(createExternalIdWithOtherCaseEmail(nextId(scheme, i)));
}
@@ -630,29 +680,30 @@
}
private ExternalId createExternalIdWithOtherCaseEmail(String externalId) {
- return ExternalId.createWithPassword(
- ExternalId.Key.parse(externalId),
+ return externalIdFactory.createWithPassword(
+ externalIdKeyFactory.parse(externalId),
admin.id(),
admin.email().toUpperCase(Locale.US),
"password");
}
private ExternalId createExternalIdForNonExistingAccount(String externalId) {
- return ExternalId.create(ExternalId.Key.parse(externalId), Account.id(1));
+ return externalIdFactory.create(externalIdKeyFactory.parse(externalId), Account.id(1));
}
private ExternalId createExternalIdWithInvalidEmail(String externalId) {
- return ExternalId.createWithEmail(
- ExternalId.Key.parse(externalId), admin.id(), "invalid-email");
+ return externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(externalId), admin.id(), "invalid-email");
}
private ExternalId createExternalIdWithDuplicateEmail(String externalId) {
- return ExternalId.createWithEmail(ExternalId.Key.parse(externalId), user.id(), admin.email());
+ return externalIdFactory.createWithEmail(
+ externalIdKeyFactory.parse(externalId), user.id(), admin.email());
}
private ExternalId createExternalIdWithBadPassword(String username) {
- return ExternalId.create(
- ExternalId.Key.create(SCHEME_USERNAME, username),
+ return externalIdFactory.create(
+ externalIdKeyFactory.create(SCHEME_USERNAME, username),
admin.id(),
null,
"non-hashed-password-is-not-allowed");
@@ -664,14 +715,14 @@
@Test
public void readExternalIdWithAccountIdThatCanBeExpressedInKiB() throws Exception {
- ExternalId.Key extIdKey = ExternalId.Key.parse("foo:bar");
+ ExternalId.Key extIdKey = externalIdKeyFactory.parse("foo:bar");
Account.Id accountId = Account.id(1024 * 100);
accountsUpdateProvider
.get()
.insert(
"Create Account with Bad External ID",
accountId,
- u -> u.addExternalId(ExternalId.create(extIdKey, accountId)));
+ u -> u.addExternalId(externalIdFactory.create(extIdKey, accountId)));
Optional<ExternalId> extId = externalIds.get(extIdKey);
assertThat(extId.map(ExternalId::accountId)).hasValue(accountId);
}
@@ -681,7 +732,7 @@
Set<ExternalId> expectedExtIds = new HashSet<>(externalIds.byAccount(admin.id()));
try (AutoCloseable ctx = createFailOnLoadContext()) {
// insert external ID
- ExternalId extId = ExternalId.create("foo", "bar", admin.id());
+ ExternalId extId = externalIdFactory.create("foo", "bar", admin.id());
insertExtId(extId);
expectedExtIds.add(extId);
assertThat(externalIds.byAccount(admin.id())).containsExactlyElementsIn(expectedExtIds);
@@ -689,7 +740,7 @@
// update external ID
expectedExtIds.remove(extId);
ExternalId extId2 =
- ExternalId.createWithEmail("foo", "bar", admin.id(), "foo.bar@example.com");
+ externalIdFactory.createWithEmail("foo", "bar", admin.id(), "foo.bar@example.com");
accountsUpdateProvider
.get()
.update("Update External ID", admin.id(), u -> u.updateExternalId(extId2));
@@ -711,7 +762,7 @@
try (AutoCloseable ctx = createFailOnLoadContext()) {
// update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id()));
+ insertExtIdBehindGerritsBack(externalIdFactory.create("foo", "bar", admin.id()));
assertThrows(IOException.class, () -> externalIds.byAccount(admin.id()));
}
@@ -723,7 +774,7 @@
try (AutoCloseable ctx = createFailOnLoadContext()) {
// update external ID branch so that external IDs need to be reloaded
- insertExtIdBehindGerritsBack(ExternalId.create("foo", "bar", admin.id()));
+ insertExtIdBehindGerritsBack(externalIdFactory.create("foo", "bar", admin.id()));
assertThrows(IOException.class, () -> externalIds.byEmail(admin.email()));
}
@@ -732,7 +783,7 @@
@Test
public void byAccountUpdateExternalIdsBehindGerritsBack() throws Exception {
Set<ExternalId> expectedExternalIds = new HashSet<>(externalIds.byAccount(admin.id()));
- ExternalId newExtId = ExternalId.create("foo", "bar", admin.id());
+ ExternalId newExtId = externalIdFactory.create("foo", "bar", admin.id());
insertExtIdBehindGerritsBack(newExtId);
expectedExternalIds.add(newExtId);
assertThat(externalIds.byAccount(admin.id())).containsExactlyElementsIn(expectedExternalIds);
@@ -740,10 +791,10 @@
@Test
public void unsetEmail() throws Exception {
- ExternalId extId = ExternalId.createWithEmail("x", "1", user.id(), "x@example.com");
+ ExternalId extId = externalIdFactory.createWithEmail("x", "1", user.id(), "x@example.com");
insertExtId(extId);
- ExternalId extIdWithoutEmail = ExternalId.create("x", "1", user.id());
+ ExternalId extIdWithoutEmail = externalIdFactory.create("x", "1", user.id());
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
@@ -757,10 +808,11 @@
@Test
public void unsetHttpPassword() throws Exception {
ExternalId extId =
- ExternalId.createWithPassword(ExternalId.Key.create("y", "1"), user.id(), null, "secret");
+ externalIdFactory.createWithPassword(
+ externalIdKeyFactory.create("y", "1"), user.id(), null, "secret");
insertExtId(extId);
- ExternalId extIdWithoutPassword = ExternalId.create("y", "1", user.id());
+ ExternalId extIdWithoutPassword = externalIdFactory.create("y", "1", user.id());
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
@@ -771,6 +823,75 @@
}
}
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseInsensitiveExternalId_DuplicateKey() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_USERNAME, "JohnDoe", Account.id(42));
+ assertThrows(
+ DuplicateExternalIdKeyException.class,
+ () ->
+ extIdNotes.insert(
+ externalIdFactory.create(SCHEME_USERNAME, "johndoe", Account.id(23))));
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseInsensitiveExternalId_SchemeWithUsername() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_USERNAME, "janedoe", Account.id(66));
+ testCaseInsensitiveExternalIdKey(md, extIdNotes, SCHEME_GERRIT, "JaneDoe", Account.id(66));
+ }
+ }
+
+ @Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void createCaseSensitiveExternalId_SchemeWithoutUsername() throws Exception {
+ try (Repository allUsersRepo = repoManager.openRepository(allUsers);
+ MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
+ ExternalIdNotes extIdNotes = externalIdNotesFactory.load(allUsersRepo);
+
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_MAILTO, "Jane@doe.com", Account.id(66));
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_UUID, "1234ABCD", Account.id(66));
+ testCaseSensitiveExternalIdKey(md, extIdNotes, SCHEME_GPGKEY, "1234ABCD", Account.id(66));
+ }
+ }
+
+ private void testCaseSensitiveExternalIdKey(
+ MetaDataUpdate md, ExternalIdNotes extIdNotes, String scheme, String id, Account.Id accountId)
+ throws DuplicateExternalIdKeyException, IOException, ConfigInvalidException {
+ ExternalId extId = externalIdFactory.create(scheme, id, accountId);
+ extIdNotes.insert(extId);
+ extIdNotes.commit(md);
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id)).get().accountId().get())
+ .isEqualTo(accountId.get());
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id.toLowerCase())).isPresent())
+ .isFalse();
+ }
+
+ private void testCaseInsensitiveExternalIdKey(
+ MetaDataUpdate md, ExternalIdNotes extIdNotes, String scheme, String id, Account.Id accountId)
+ throws DuplicateExternalIdKeyException, IOException, ConfigInvalidException {
+ ExternalId extId = externalIdFactory.create(scheme, id, accountId);
+ extIdNotes.insert(extId);
+ extIdNotes.commit(md);
+ assertThat(extIdNotes.get(externalIdKeyFactory.create(scheme, id)).get().accountId().get())
+ .isEqualTo(accountId.get());
+ assertThat(
+ extIdNotes
+ .get(externalIdKeyFactory.create(scheme, id.toLowerCase()))
+ .get()
+ .accountId()
+ .get())
+ .isEqualTo(accountId.get());
+ }
+
private boolean isPartialCacheReloadingEnabled() {
return cfg.getBoolean("cache", "external_ids_map", "enablePartialReloads", true);
}
@@ -796,7 +917,8 @@
private void insertExtIdBehindGerritsBack(ExternalId extId) throws Exception {
try (Repository repo = repoManager.openRepository(allUsers)) {
// Inserting an external ID "behind Gerrit's back" means that the caches are not updated.
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(allUsers, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(allUsers, repo, externalIdFactory);
extIdNotes.insert(extId);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, null, repo)) {
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/GetAccountDetailIT.java b/javatests/com/google/gerrit/acceptance/rest/account/GetAccountDetailIT.java
index 84f95f7..a1e9bf1 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/GetAccountDetailIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/GetAccountDetailIT.java
@@ -17,22 +17,42 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.rest.account.AccountAssert.assertAccountInfo;
+import com.google.common.collect.ImmutableList;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.group.GroupOperations;
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
+import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.common.AccountDetailInfo;
import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.server.account.AccountTagProvider;
import com.google.gerrit.server.account.ServiceUserClassifier;
+import com.google.gerrit.server.permissions.GlobalPermission;
+import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.inject.Inject;
+import com.google.inject.Module;
+import java.util.List;
import org.junit.Test;
public class GetAccountDetailIT extends AbstractDaemonTest {
@Inject private GroupOperations groupOperations;
@Inject private AccountOperations accountOperations;
+ @Override
+ public Module createModule() {
+ return new FactoryModule() {
+ @Override
+ public void configure() {
+ bind(AccountTagProvider.class)
+ .annotatedWith(Exports.named("CustomAccountTagProvider"))
+ .to(CustomAccountTagProvider.class);
+ }
+ };
+ }
+
@Test
public void getDetail() throws Exception {
RestResponse r = adminRestSession.get("/accounts/" + admin.username() + "/detail/");
@@ -56,7 +76,14 @@
.update();
RestResponse r = adminRestSession.get("/accounts/" + serviceUser.get() + "/detail/");
AccountDetailInfo info = newGson().fromJson(r.getReader(), AccountDetailInfo.class);
- assertThat(info.tags).containsExactly(AccountInfo.Tag.SERVICE_USER);
+ assertThat(info.tags).containsExactly(AccountInfo.Tags.SERVICE_USER);
+ }
+
+ @Test
+ public void getDetailForExtensionPointAccountTag() throws Exception {
+ RestResponse r = userRestSession.get("/accounts/" + user.username() + "/detail/");
+ AccountDetailInfo info = newGson().fromJson(r.getReader(), AccountDetailInfo.class);
+ assertThat(info.tags).containsExactly("BASIC_USER");
}
@Test
@@ -75,4 +102,25 @@
AccountDetailInfo info = newGson().fromJson(r.getReader(), AccountDetailInfo.class);
assertThat(info._accountId).isEqualTo(id.get());
}
+
+ private static class CustomAccountTagProvider implements AccountTagProvider {
+ private PermissionBackend permissions;
+
+ @Inject
+ public CustomAccountTagProvider(PermissionBackend permissions) {
+ this.permissions = permissions;
+ }
+
+ @Override
+ public List<String> getTags(Account.Id id) {
+ try {
+ if (!permissions.currentUser().test(GlobalPermission.ADMINISTRATE_SERVER)) {
+ return ImmutableList.of("BASIC_USER");
+ }
+ } catch (Exception e) {
+ throw new IllegalStateException("can't check admin permissions", e);
+ }
+ return ImmutableList.of();
+ }
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java b/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
index e05d0db..f46cf0c 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/PutUsernameIT.java
@@ -18,6 +18,7 @@
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.extensions.api.accounts.UsernameInput;
import org.junit.Test;
@@ -42,6 +43,16 @@
}
@Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void setExistingCaseInsensitive_Conflict() throws Exception {
+ UsernameInput in = new UsernameInput();
+ in.username = admin.username().toUpperCase();
+ adminRestSession
+ .put("/accounts/" + accountCreator.create().id().get() + "/username", in)
+ .assertConflict();
+ }
+
+ @Test
public void setNew_MethodNotAllowed() throws Exception {
UsernameInput in = new UsernameInput();
in.username = "newUsername";
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
index eb125a0..13353bd 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/AccountsRestApiBindingsIT.java
@@ -29,7 +29,7 @@
import com.google.gerrit.gpg.testing.TestKey;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.junit.Test;
@@ -43,6 +43,7 @@
public class AccountsRestApiBindingsIT extends AbstractDaemonTest {
@Inject private @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider;
@Inject private RequestScopeOperations requestScopeOperations;
+ @Inject private ExternalIdFactory externalIdFactory;
/**
* Account REST endpoints to be tested, each URL contains a placeholder for the account
@@ -86,7 +87,6 @@
RestCall.get("/accounts/%s/preferences.edit"),
RestCall.put("/accounts/%s/preferences.edit"),
RestCall.get("/accounts/%s/starred.changes"),
- RestCall.get("/accounts/%s/stars.changes"),
RestCall.post("/accounts/%s/index"),
RestCall.get("/accounts/%s/agreements"),
RestCall.put("/accounts/%s/agreements"),
@@ -141,9 +141,7 @@
private static final ImmutableList<RestCall> STAR_ENDPOINTS =
ImmutableList.of(
RestCall.put("/accounts/%s/starred.changes/%s"),
- RestCall.delete("/accounts/%s/starred.changes/%s"),
- RestCall.get("/accounts/%s/stars.changes/%s"),
- RestCall.post("/accounts/%s/stars.changes/%s"));
+ RestCall.delete("/accounts/%s/starred.changes/%s"));
@Test
public void accountEndpoints() throws Exception {
@@ -169,7 +167,7 @@
admin.id(),
u ->
u.addExternalId(
- ExternalId.createWithEmail(name("test"), email, admin.id(), email)));
+ externalIdFactory.createWithEmail(name("test"), email, admin.id(), email)));
requestScopeOperations.setApiUser(admin.id());
gApi.accounts()
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
index 68b24ce..79484ca 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
@@ -76,8 +76,6 @@
RestCall.post("/changes/%s/ready"),
RestCall.put("/changes/%s/ignore"),
RestCall.put("/changes/%s/unignore"),
- RestCall.put("/changes/%s/reviewed"),
- RestCall.put("/changes/%s/unreviewed"),
RestCall.get("/changes/%s/messages"),
RestCall.put("/changes/%s/message"),
RestCall.post("/changes/%s/merge"),
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
index bcca8bb..0a11b15 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/AttentionSetIT.java
@@ -64,7 +64,6 @@
import com.google.gerrit.server.restapi.change.GetAttentionSet;
import com.google.gerrit.server.util.AccountTemplateUtil;
import com.google.gerrit.server.util.time.TimeUtil;
-import com.google.gerrit.testing.FakeEmailSender;
import com.google.gerrit.testing.TestCommentHelper;
import com.google.gerrit.truth.NullAwareCorrespondence;
import com.google.inject.Inject;
@@ -89,7 +88,6 @@
@Inject private AccountOperations accountOperations;
@Inject private RequestScopeOperations requestScopeOperations;
- @Inject private FakeEmailSender email;
@Inject private TestCommentHelper testCommentHelper;
@Inject private Provider<InternalChangeQuery> changeQueryProvider;
@Inject private ProjectOperations projectOperations;
@@ -145,7 +143,7 @@
assertThat(r.getChange().attentionSet()).containsExactly(expectedAttentionSetUpdate);
// Only one email since the second add was ignored.
- String emailBody = Iterables.getOnlyElement(email.getMessages()).body();
+ String emailBody = Iterables.getOnlyElement(sender.getMessages()).body();
assertThat(emailBody)
.contains(
String.format(
@@ -218,7 +216,6 @@
ReviewInput.create().addUserToAttentionSet(user.email(), manualReason);
change(r).current().review(reviewInput);
-
AttentionSetInfo attentionSetInfo = change(r).get().attentionSet.get(user.id().get());
assertThat(attentionSetInfo.reason).isEqualTo(manualReason);
assertThat(attentionSetInfo.reasonAccount).isEqualTo(getAccountInfo(user.id()));
@@ -270,7 +267,7 @@
assertThat(r.getChange().attentionSet()).containsExactly(expectedAttentionSetUpdate);
// Only one email since the second remove was ignored.
- String emailBody = Iterables.getOnlyElement(email.getMessages()).body();
+ String emailBody = Iterables.getOnlyElement(sender.getMessages()).body();
assertThat(emailBody)
.contains(
user.fullName()
@@ -706,7 +703,7 @@
assertThat(attentionSet).hasReasonThat().isEqualTo("reason");
// No emails for adding to attention set were sent.
- assertThat(email.getMessages()).isEmpty();
+ assertThat(sender.getMessages()).isEmpty();
}
@Test
@@ -715,7 +712,7 @@
// implictly adds the user to the attention set when adding as reviewer
change(r).addReviewer(user.email());
requestScopeOperations.setApiUser(user.id());
- email.clear();
+ sender.clear();
ReviewInput reviewInput =
ReviewInput.create().removeUserFromAttentionSet(user.email(), "reason");
@@ -728,7 +725,7 @@
assertThat(attentionSet).hasReasonThat().isEqualTo("reason");
// No emails for removing from attention set were sent.
- assertThat(email.getMessages()).isEmpty();
+ assertThat(sender.getMessages()).isEmpty();
}
@Test
@@ -1537,6 +1534,45 @@
}
@Test
+ public void addToAttentionSetEmail_withTemplateReason() throws Exception {
+ PushOneCommit.Result r = createChange();
+ requestScopeOperations.setApiUser(user.id());
+ String templateReason = "Added by " + AccountTemplateUtil.getAccountTemplate(user.id());
+ int accountId =
+ change(r)
+ .addToAttentionSet(new AttentionSetInput(admin.email(), templateReason))
+ ._accountId;
+
+ assertThat(accountId).isEqualTo(admin.id().get());
+ String emailBody = Iterables.getOnlyElement(sender.getMessages()).body();
+ assertThat(emailBody)
+ .contains(
+ String.format(
+ "%s requires the attention of %s to this change.\n The reason is: Added by %s.",
+ user.fullName(), admin.fullName(), user.getNameEmail()));
+ }
+
+ @Test
+ public void removeFromAttentionSetEmail_withTemplateReason() throws Exception {
+ PushOneCommit.Result r = createChange();
+ // implicitly adds the user to the attention set when adding as reviewer
+ change(r).addReviewer(user.email());
+ sender.clear();
+ requestScopeOperations.setApiUser(user.id());
+
+ String templateReason = "Removed by " + AccountTemplateUtil.getAccountTemplate(user.id());
+ change(r).attention(user.id().toString()).remove(new AttentionSetInput(templateReason));
+
+ String emailBody = Iterables.getOnlyElement(sender.getMessages()).body();
+ assertThat(emailBody)
+ .contains(
+ String.format(
+ "%s removed themselves from the attention set of this change.\n"
+ + " The reason is: Removed by %s.",
+ user.fullName(), user.getNameEmail()));
+ }
+
+ @Test
public void attentionSetEmailFooter() throws Exception {
PushOneCommit.Result r = createChange();
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/CorsIT.java b/javatests/com/google/gerrit/acceptance/rest/change/CorsIT.java
index 61e5a2e..ae872b2b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/CorsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/CorsIT.java
@@ -27,6 +27,7 @@
import static com.google.common.net.HttpHeaders.VARY;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.common.truth.TruthJUnit.assume;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
@@ -41,6 +42,7 @@
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.server.UrlEncoded;
import com.google.gerrit.testing.ConfigSuite;
+import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.stream.Stream;
@@ -206,6 +208,10 @@
@Test
public void crossDomainPutTopic() throws Exception {
+ // Setting cookies with HttpOnly requires Servlet API 3+ which not all deployments might have
+ // available.
+ assume().that(cookieHasSetHttpOnlyMethod()).isTrue();
+
Result change = createChange();
BasicCookieStore cookies = new BasicCookieStore();
Executor http = Executor.newInstance().use(cookies);
@@ -327,4 +333,14 @@
assertWithMessage(ACCESS_CONTROL_ALLOW_HEADERS).that(allowHeaders).isNull();
}
}
+
+ private static boolean cookieHasSetHttpOnlyMethod() {
+ Method setHttpOnly = null;
+ try {
+ setHttpOnly = Cookie.class.getMethod("setHttpOnly", boolean.class);
+ } catch (NoSuchMethodException | SecurityException e) {
+ return false;
+ }
+ return setHttpOnly != null;
+ }
}
diff --git a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
index ad06226..b0a14cf 100644
--- a/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/change/CreateChangeIT.java
@@ -54,6 +54,7 @@
import com.google.gerrit.extensions.api.projects.BranchInput;
import com.google.gerrit.extensions.client.ChangeStatus;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
+import com.google.gerrit.extensions.client.ReviewerState;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeInput;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
@@ -420,6 +421,69 @@
}
@Test
+ public void createAuthorAddedAsCcAndNotified() throws Exception {
+ ChangeInput input = newChangeInput(ChangeStatus.NEW);
+ input.author = new AccountInput();
+ input.author.email = user.email();
+ input.author.name = user.fullName();
+
+ ChangeInfo info = assertCreateSucceeds(input);
+ assertThat(info.reviewers.get(ReviewerState.CC)).hasSize(1);
+ assertThat(Iterables.getOnlyElement(info.reviewers.get(ReviewerState.CC)).email)
+ .isEqualTo(user.email());
+ assertThat(
+ Iterables.getOnlyElement(Iterables.getOnlyElement(sender.getMessages()).rcpt()).email())
+ .isEqualTo(user.email());
+ }
+
+ @Test
+ public void createAuthorAddedAsCcNotNotifiedWithNotifyNone() throws Exception {
+ ChangeInput input = newChangeInput(ChangeStatus.NEW);
+ input.author = new AccountInput();
+ input.author.email = user.email();
+ input.author.name = user.fullName();
+ input.notify = NotifyHandling.NONE;
+
+ ChangeInfo info = assertCreateSucceeds(input);
+ assertThat(info.reviewers.get(ReviewerState.CC)).hasSize(1);
+ assertThat(Iterables.getOnlyElement(info.reviewers.get(ReviewerState.CC)).email)
+ .isEqualTo(user.email());
+ assertThat(sender.getMessages()).isEmpty();
+ }
+
+ @Test
+ public void createWithMergeConflictAuthorAddedAsCcNotNotifiedWithNotifyNone() throws Exception {
+ String fileName = "shared.txt";
+ String sourceBranch = "sourceBranch";
+ String sourceSubject = "source change";
+ String sourceContent = "source content";
+ String targetBranch = "targetBranch";
+ String targetSubject = "target change";
+ String targetContent = "target content";
+ changeInTwoBranches(
+ sourceBranch,
+ sourceSubject,
+ fileName,
+ sourceContent,
+ targetBranch,
+ targetSubject,
+ fileName,
+ targetContent);
+ ChangeInput input = newMergeChangeInput(targetBranch, sourceBranch, "", true);
+ input.workInProgress = true;
+ input.author = new AccountInput();
+ input.author.email = user.email();
+ input.author.name = user.fullName();
+ input.notify = NotifyHandling.NONE;
+ ChangeInfo info = assertCreateSucceeds(input);
+
+ assertThat(info.reviewers.get(ReviewerState.CC)).hasSize(1);
+ assertThat(Iterables.getOnlyElement(info.reviewers.get(ReviewerState.CC)).email)
+ .isEqualTo(user.email());
+ assertThat(sender.getMessages()).isEmpty();
+ }
+
+ @Test
public void createNewWorkInProgressChange() throws Exception {
ChangeInput input = newChangeInput(ChangeStatus.NEW);
input.workInProgress = true;
@@ -1117,7 +1181,6 @@
* @param branchB name of second branch to create
* @param fileB name of file to commit to branchB
* @return A {@code Map} of branchName => commit result.
- * @throws Exception
*/
private Map<String, Result> changeInTwoBranches(
String branchA, String fileA, String branchB, String fileB) throws Exception {
@@ -1137,7 +1200,6 @@
* @param fileB name of file to commit to branchB
* @param contentB file content to commit to branchB
* @return A {@code Map} of branchName => commit result.
- * @throws Exception
*/
private Map<String, Result> changeInTwoBranches(
String branchA,
diff --git a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
index daeb032..ef5e7dc 100644
--- a/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/config/CacheOperationsIT.java
@@ -52,14 +52,14 @@
}
@Test
- public void flushAll_Forbidden() throws Exception {
+ public void flushAll_forbidden() throws Exception {
userRestSession
.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL))
.assertForbidden();
}
@Test
- public void flushAll_BadRequest() throws Exception {
+ public void flushAll_badRequest() throws Exception {
adminRestSession
.post("/config/server/caches/", new PostCaches.Input(FLUSH_ALL, Arrays.asList("projects")))
.assertBadRequest();
diff --git a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
index 02db412..5f60250 100644
--- a/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/project/CreateProjectIT.java
@@ -102,12 +102,12 @@
}
@Test
- public void createProjectHttpWhenProjectAlreadyExists_Conflict() throws Exception {
+ public void createProjectHttpWhenProjectAlreadyExists_conflict() throws Exception {
adminRestSession.put("/projects/" + allProjects.get()).assertConflict();
}
@Test
- public void createProjectHttpWhenProjectAlreadyExists_PreconditionFailed() throws Exception {
+ public void createProjectHttpWhenProjectAlreadyExists_preconditionFailed() throws Exception {
adminRestSession
.putWithHeaders(
"/projects/" + allProjects.get(), new BasicHeader(HttpHeaders.IF_NONE_MATCH, "*"))
@@ -140,7 +140,7 @@
@Test
@UseLocalDisk
- public void createProjectHttpWithUnreasonableName_BadRequest() throws Exception {
+ public void createProjectHttpWithUnreasonableName_badRequest() throws Exception {
ImmutableList<String> forbiddenStrings =
ImmutableList.of(
"/../", "/./", "//", ".git/", "?", "%", "*", ":", "<", ">", "|", "$", "/+", "~");
@@ -153,14 +153,14 @@
}
@Test
- public void createProjectHttpWithNameMismatch_BadRequest() throws Exception {
+ public void createProjectHttpWithNameMismatch_badRequest() throws Exception {
ProjectInput in = new ProjectInput();
in.name = name("otherName");
adminRestSession.put("/projects/" + name("someName"), in).assertBadRequest();
}
@Test
- public void createProjectHttpWithInvalidRefName_BadRequest() throws Exception {
+ public void createProjectHttpWithInvalidRefName_badRequest() throws Exception {
ProjectInput in = new ProjectInput();
in.branches = Collections.singletonList(name("invalid ref name"));
adminRestSession.put("/projects/" + name("newProject"), in).assertBadRequest();
diff --git a/javatests/com/google/gerrit/acceptance/rest/util/RestApiCallHelper.java b/javatests/com/google/gerrit/acceptance/rest/util/RestApiCallHelper.java
index f98fb45..55735fc 100644
--- a/javatests/com/google/gerrit/acceptance/rest/util/RestApiCallHelper.java
+++ b/javatests/com/google/gerrit/acceptance/rest/util/RestApiCallHelper.java
@@ -29,13 +29,13 @@
/** Helper to execute REST API calls using the HTTP client. */
@Ignore
public class RestApiCallHelper {
- /** @see #execute(RestSession, List, BeforeRestCall, String...) */
+ /** See {@link #execute(RestSession, List, BeforeRestCall, String...)} */
public static void execute(RestSession restSession, List<RestCall> restCalls, String... args)
throws Exception {
execute(restSession, restCalls, () -> {}, args);
}
- /** @see #execute(RestSession, List, BeforeRestCall, String...) */
+ /** See {@link #execute(RestSession, RestCall, String...)} */
public static void execute(
RestSession restSession,
List<RestCall> restCalls,
diff --git a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
index c7beb2d..0cfa0f8 100644
--- a/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/account/AccountResolverIT.java
@@ -23,6 +23,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.account.AccountOperations;
import com.google.gerrit.acceptance.testsuite.account.TestAccount;
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
@@ -160,6 +161,22 @@
}
@Test
+ @GerritConfig(name = "auth.userNameCaseInsensitive", value = "true")
+ public void byUsernameCaseInsensitive() throws Exception {
+ String existingUsername = "myusername";
+ Account.Id idWithUsername = accountOperations.newAccount().username(existingUsername).create();
+
+ String existingMixedCaseUsername = "MyMixedCaseUsername";
+ Account.Id idWithMixedCaseUsername =
+ accountOperations.newAccount().username(existingMixedCaseUsername).create();
+
+ assertThat(resolve(existingUsername)).containsExactly(idWithUsername);
+ assertThat(resolve(existingMixedCaseUsername)).containsExactly(idWithMixedCaseUsername);
+ assertThat(resolve(existingMixedCaseUsername.toLowerCase()))
+ .containsExactly(idWithMixedCaseUsername);
+ }
+
+ @Test
public void byNameAndEmail() throws Exception {
String email = name("user@example.com");
Account.Id idWithEmail = accountOperations.newAccount().preferredEmail(email).create();
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
index 81cb7159..a2765d9 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentContextIT.java
@@ -425,7 +425,7 @@
}
@Test
- public void commentContextReturnsCorrectContentType_Java() throws Exception {
+ public void commentContextReturnsCorrectContentType_java() throws Exception {
String javaContent =
"public class Main {\n"
+ " public static void main(String[]args){\n"
@@ -448,7 +448,7 @@
}
@Test
- public void commentContextReturnsCorrectContentType_Cpp() throws Exception {
+ public void commentContextReturnsCorrectContentType_cpp() throws Exception {
String cppContent =
"#include <iostream>\n"
+ "\n"
diff --git a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
index 89074b7..80cdad8 100644
--- a/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/change/CommentsIT.java
@@ -224,12 +224,14 @@
String ps1 = result.getCommit().name();
CommentInput comment =
- CommentsUtil.newCommentWithOnlyMandatoryFields(PATCHSET_LEVEL, "comment");
+ CommentsUtil.newCommentWithOnlyMandatoryFields(
+ PATCHSET_LEVEL, "The change looks good, LGTM");
CommentsUtil.addComments(gApi, changeId, ps1, comment);
String emailBody = Iterables.getOnlyElement(email.getMessages()).body();
assertThat(emailBody).contains("Patchset");
assertThat(emailBody).doesNotContain("/PATCHSET_LEVEL");
+ assertThat(emailBody).contains("The change looks good, LGTM");
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java b/javatests/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
deleted file mode 100644
index b23f9a3..0000000
--- a/javatests/com/google/gerrit/acceptance/server/change/PatchListCacheIT.java
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright (C) 2014 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.change;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.acceptance.GitUtil.getChangeId;
-import static com.google.gerrit.acceptance.GitUtil.pushHead;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import com.google.common.cache.Cache;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
-import com.google.gerrit.acceptance.NoHttpd;
-import com.google.gerrit.entities.Patch;
-import com.google.gerrit.entities.Patch.ChangeType;
-import com.google.gerrit.extensions.client.DiffPreferencesInfo.Whitespace;
-import com.google.gerrit.server.patch.IntraLineDiff;
-import com.google.gerrit.server.patch.IntraLineDiffArgs;
-import com.google.gerrit.server.patch.IntraLineDiffKey;
-import com.google.gerrit.server.patch.PatchList;
-import com.google.gerrit.server.patch.PatchListCache;
-import com.google.gerrit.server.patch.PatchListCacheImpl;
-import com.google.gerrit.server.patch.PatchListEntry;
-import com.google.gerrit.server.patch.PatchListKey;
-import com.google.gerrit.server.patch.Text;
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import org.eclipse.jgit.diff.Edit;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.junit.Test;
-
-@NoHttpd
-public class PatchListCacheIT extends AbstractDaemonTest {
- private static String SUBJECT_1 = "subject 1";
- private static String SUBJECT_2 = "subject 2";
- private static String SUBJECT_3 = "subject 3";
- private static String FILE_A = "a.txt";
- private static String FILE_B = "b.txt";
- private static String FILE_C = "c.txt";
- private static String FILE_D = "d.txt";
-
- @Inject private PatchListCache patchListCache;
-
- @Inject
- @Named("diff")
- private Cache<PatchListKey, PatchList> abstractPatchListCache;
-
- @Test
- public void ensureLegacyBackendIsUsedForFileCacheBackend() throws Exception {
- Field fileCacheField = patchListCache.getClass().getDeclaredField("fileCache");
- fileCacheField.setAccessible(true);
- // Use the reflection to access "localCache" field that is only present in Guava backend.
- assertThat(
- Arrays.stream(fileCacheField.get(patchListCache).getClass().getDeclaredFields())
- .anyMatch(f -> f.getName().equals("localCache")))
- .isTrue();
-
- // intraCache (and all other cache backends) should use Caffeine backend.
- Field intraCacheField = patchListCache.getClass().getDeclaredField("intraCache");
- intraCacheField.setAccessible(true);
- assertThat(
- Arrays.stream(intraCacheField.get(patchListCache).getClass().getDeclaredFields())
- .noneMatch(f -> f.getName().equals("localCache")))
- .isTrue();
- }
-
- @Test
- public void listPatchesAgainstBase() throws Exception {
- commitBuilder().add(FILE_D, "4").message(SUBJECT_1).create();
- pushHead(testRepo, "refs/heads/master", false);
-
- // Change 1, 1 (+FILE_A, -FILE_D)
- RevCommit c =
- commitBuilder().add(FILE_A, "1").rm(FILE_D).message(SUBJECT_2).insertChangeId().create();
- String id = getChangeId(testRepo, c).get();
- pushHead(testRepo, "refs/for/master", false);
-
- // Compare Change 1,1 with Base (+FILE_A, -FILE_D)
- List<PatchListEntry> entries = getCurrentPatches(id);
- assertThat(entries).hasSize(3);
- assertAdded(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_A, entries.get(1));
- assertDeleted(FILE_D, entries.get(2));
-
- // Change 1,2 (+FILE_A, +FILE_B, -FILE_D)
- amendBuilder().add(FILE_B, "2").create();
- pushHead(testRepo, "refs/for/master", false);
- entries = getCurrentPatches(id);
-
- // Compare Change 1,2 with Base (+FILE_A, +FILE_B, -FILE_D)
- assertThat(entries).hasSize(4);
- assertAdded(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_A, entries.get(1));
- assertAdded(FILE_B, entries.get(2));
- assertDeleted(FILE_D, entries.get(3));
- }
-
- @Test
- public void listPatchesAgainstBaseWithRebase() throws Exception {
- commitBuilder().add(FILE_D, "4").message(SUBJECT_1).create();
- pushHead(testRepo, "refs/heads/master", false);
-
- // Change 1,1 (+FILE_A, -FILE_D)
- RevCommit c = commitBuilder().add(FILE_A, "1").rm(FILE_D).message(SUBJECT_2).create();
- String id = getChangeId(testRepo, c).get();
- pushHead(testRepo, "refs/for/master", false);
- List<PatchListEntry> entries = getCurrentPatches(id);
- assertThat(entries).hasSize(3);
- assertAdded(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_A, entries.get(1));
- assertDeleted(FILE_D, entries.get(2));
-
- // Change 2,1 (+FILE_B)
- testRepo.reset("HEAD~1");
- commitBuilder().add(FILE_B, "2").message(SUBJECT_3).create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Change 1,2 (+FILE_A, -FILE_D))
- testRepo.cherryPick(c);
- pushHead(testRepo, "refs/for/master", false);
-
- // Compare Change 1,2 with Base (+FILE_A, -FILE_D))
- entries = getCurrentPatches(id);
- assertThat(entries).hasSize(3);
- assertAdded(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_A, entries.get(1));
- assertDeleted(FILE_D, entries.get(2));
- }
-
- @Test
- public void listPatchesAgainstOtherPatchSet() throws Exception {
- commitBuilder().add(FILE_D, "4").message(SUBJECT_1).create();
- pushHead(testRepo, "refs/heads/master", false);
-
- // Change 1,1 (+FILE_A, +FILE_C, -FILE_D)
- RevCommit a =
- commitBuilder().add(FILE_A, "1").add(FILE_C, "3").rm(FILE_D).message(SUBJECT_2).create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Change 1,2 (+FILE_A, +FILE_B, -FILE_D)
- RevCommit b = amendBuilder().add(FILE_B, "2").rm(FILE_C).create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Compare Change 1,1 with Change 1,2 (+FILE_B, -FILE_C)
- List<PatchListEntry> entries = getPatches(a, b);
- assertThat(entries).hasSize(3);
- assertModified(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_B, entries.get(1));
- assertDeleted(FILE_C, entries.get(2));
-
- // Compare Change 1,2 with Change 1,1 (-FILE_B, +FILE_C)
- List<PatchListEntry> entriesReverse = getPatches(b, a);
- assertThat(entriesReverse).hasSize(3);
- assertModified(Patch.COMMIT_MSG, entriesReverse.get(0));
- assertDeleted(FILE_B, entriesReverse.get(1));
- assertAdded(FILE_C, entriesReverse.get(2));
- }
-
- @Test
- public void listPatchesAgainstOtherPatchSetWithRebase() throws Exception {
- commitBuilder().add(FILE_D, "4").message(SUBJECT_1).create();
- pushHead(testRepo, "refs/heads/master", false);
-
- // Change 1,1 (+FILE_A, -FILE_D)
- RevCommit a = commitBuilder().add(FILE_A, "1").rm(FILE_D).message(SUBJECT_2).create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Change 2,1 (+FILE_B)
- testRepo.reset("HEAD~1");
- commitBuilder().add(FILE_B, "2").message(SUBJECT_3).create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Change 1,2 (+FILE_A, +FILE_C, -FILE_D)
- testRepo.cherryPick(a);
- RevCommit b = amendBuilder().add(FILE_C, "2").create();
- pushHead(testRepo, "refs/for/master", false);
-
- // Compare Change 1,1 with Change 1,2 (+FILE_C)
- List<PatchListEntry> entries = getPatches(a, b);
- assertThat(entries).hasSize(2);
- assertModified(Patch.COMMIT_MSG, entries.get(0));
- assertAdded(FILE_C, entries.get(1));
-
- // Compare Change 1,2 with Change 1,1 (-FILE_C)
- List<PatchListEntry> entriesReverse = getPatches(b, a);
- assertThat(entriesReverse).hasSize(2);
- assertModified(Patch.COMMIT_MSG, entriesReverse.get(0));
- assertDeleted(FILE_C, entriesReverse.get(1));
- }
-
- @Test
- public void harmfulMutationsOfEditsAreNotPossibleForPatchListEntry() throws Exception {
- RevCommit commit =
- commitBuilder().add("a.txt", "First line\nSecond line\n").message(SUBJECT_1).create();
- pushHead(testRepo, "refs/heads/master", false);
-
- PatchListKey diffKey = PatchListKey.againstDefaultBase(commit.copy(), Whitespace.IGNORE_NONE);
- PatchList patchList = patchListCache.get(diffKey, project);
-
- PatchListEntry patchListEntry = getEntryFor(patchList, "a.txt");
- Edit outputEdit = Iterables.getOnlyElement(patchListEntry.getEdits());
- Edit originalEdit =
- new Edit(
- outputEdit.getBeginA(),
- outputEdit.getEndA(),
- outputEdit.getBeginB(),
- outputEdit.getEndB());
-
- outputEdit.shift(5);
-
- assertThat(patchListEntry.getEdits()).containsExactly(originalEdit);
- }
-
- @Test
- public void harmfulMutationsOfEditsAreNotPossibleForIntraLineDiffArgsAndCachedValue() {
- String a = "First line\nSecond line\n";
- String b = "1st line\n2nd line\n";
- Text aText = new Text(a.getBytes(UTF_8));
- Text bText = new Text(b.getBytes(UTF_8));
- Edit inputEdit = new Edit(0, 2, 0, 2);
- List<Edit> inputEdits = new ArrayList<>(ImmutableList.of(inputEdit));
- Set<Edit> inputEditsDueToRebase = new HashSet<>(ImmutableSet.of(inputEdit));
-
- IntraLineDiffKey diffKey =
- IntraLineDiffKey.create(ObjectId.zeroId(), ObjectId.zeroId(), Whitespace.IGNORE_NONE);
- IntraLineDiffArgs diffArgs =
- IntraLineDiffArgs.create(
- aText,
- bText,
- inputEdits,
- inputEditsDueToRebase,
- project,
- ObjectId.zeroId(),
- "file.txt");
- IntraLineDiff intraLineDiff = patchListCache.getIntraLineDiff(diffKey, diffArgs);
-
- Edit outputEdit = Iterables.getOnlyElement(intraLineDiff.getEdits());
-
- outputEdit.shift(5);
- inputEdit.shift(7);
- inputEdits.add(new Edit(43, 47, 50, 51));
- inputEditsDueToRebase.add(new Edit(53, 57, 60, 61));
-
- Edit originalEdit = new Edit(0, 2, 0, 2);
- assertThat(diffArgs.edits()).containsExactly(originalEdit);
- assertThat(diffArgs.editsDueToRebase()).containsExactly(originalEdit);
- assertThat(intraLineDiff.getEdits()).containsExactly(originalEdit);
- }
-
- @Test
- public void largeObjectTombstoneGetsCached() {
- PatchListKey key = PatchListKey.againstDefaultBase(ObjectId.zeroId(), Whitespace.IGNORE_ALL);
- PatchListCacheImpl.LargeObjectTombstone tombstone =
- new PatchListCacheImpl.LargeObjectTombstone();
- abstractPatchListCache.put(key, tombstone);
- assertThat(abstractPatchListCache.getIfPresent(key)).isSameInstanceAs(tombstone);
- }
-
- private static void assertAdded(String expectedNewName, PatchListEntry e) {
- assertName(expectedNewName, e);
- assertThat(e.getChangeType()).isEqualTo(ChangeType.ADDED);
- }
-
- private static void assertModified(String expectedNewName, PatchListEntry e) {
- assertName(expectedNewName, e);
- assertThat(e.getChangeType()).isEqualTo(ChangeType.MODIFIED);
- }
-
- private static void assertDeleted(String expectedNewName, PatchListEntry e) {
- assertName(expectedNewName, e);
- assertThat(e.getChangeType()).isEqualTo(ChangeType.DELETED);
- }
-
- private static void assertName(String expectedNewName, PatchListEntry e) {
- assertThat(e.getNewName()).isEqualTo(expectedNewName);
- assertThat(e.getOldName()).isNull();
- }
-
- private List<PatchListEntry> getCurrentPatches(String changeId) throws Exception {
- return patchListCache.get(getKey(null, getCurrentRevisionId(changeId)), project).getPatches();
- }
-
- private List<PatchListEntry> getPatches(ObjectId revisionIdA, ObjectId revisionIdB)
- throws Exception {
- return patchListCache.get(getKey(revisionIdA, revisionIdB), project).getPatches();
- }
-
- private PatchListKey getKey(ObjectId revisionIdA, ObjectId revisionIdB) {
- return PatchListKey.againstCommit(revisionIdA, revisionIdB, Whitespace.IGNORE_NONE);
- }
-
- private ObjectId getCurrentRevisionId(String changeId) throws Exception {
- return ObjectId.fromString(gApi.changes().id(changeId).get().currentRevision);
- }
-
- private static PatchListEntry getEntryFor(PatchList patchList, String filePath) {
- Optional<PatchListEntry> patchListEntry =
- patchList.getPatches().stream()
- .filter(entry -> entry.getNewName().equals(filePath))
- .findAny();
- return patchListEntry.orElseThrow(
- () -> new IllegalStateException("No PatchListEntry for " + filePath + " exists"));
- }
-}
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java b/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
index d767f48..cb1a679 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/AbstractMailIT.java
@@ -93,8 +93,9 @@
* @param f1 Comment on file one.
* @return A string with all inline comments and the original quoted email.
*/
- static String newPlaintextBody(String changeURL, String changeMessage, String c1, String f1) {
- return (changeMessage == null ? "" : changeMessage + "\n")
+ static String newPlaintextBody(
+ String changeURL, String patchsetLevelComment, String c1, String f1) {
+ return (patchsetLevelComment == null ? "" : patchsetLevelComment + "\n")
+ "> Foo Bar has posted comments on this change. ( \n"
+ "> "
+ changeURL
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
index 65cb97a..85238f8 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/ChangeNotificationsIT.java
@@ -301,6 +301,32 @@
addReviewerToReviewableChange(batch());
}
+ private void addReviewerToIgnoredChange(Adder adder) throws Exception {
+ StagedChange sc = stageReviewableChange();
+ requestScopeOperations.setApiUser(sc.reviewer.id());
+ gApi.changes().id(sc.changeId).ignore(true);
+ TestAccount addedReviewer = accountCreator.create("added", "added@example.com", "added", null);
+ addReviewer(adder, sc.changeId, sc.owner, addedReviewer.email(), CC_ON_OWN_COMMENTS, null);
+
+ assertThat(sender)
+ .sent("newchange", sc)
+ .to(addedReviewer)
+ .cc(sc.owner)
+ .cc(StagedUsers.REVIEWER_BY_EMAIL, StagedUsers.CC_BY_EMAIL)
+ .noOneElse();
+ assertThat(sender).didNotSend();
+ }
+
+ @Test
+ public void addReviewerToIgnoredChangeSingly() throws Exception {
+ addReviewerToIgnoredChange(singly());
+ }
+
+ @Test
+ public void addReviewerToIgnoredChangeBatch() throws Exception {
+ addReviewerToIgnoredChange(batch());
+ }
+
private void addReviewerToReviewableChangeByOwnerCcingSelf(Adder adder) throws Exception {
StagedChange sc = stageReviewableChange();
TestAccount reviewer = accountCreator.create("added", "added@example.com", "added", null);
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
index 85c0212..06d9349 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
@@ -17,6 +17,7 @@
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.block;
+import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
@@ -97,7 +98,7 @@
}
@Test
- public void parseAndPersistChangeMessage() throws Exception {
+ public void parseAndPersistPatchsetLevelComment() throws Exception {
String changeId = createChangeWithReview();
ChangeInfo changeInfo = gApi.changes().id(changeId).get();
String ts =
@@ -114,8 +115,19 @@
Collection<ChangeMessageInfo> messages = gApi.changes().id(changeId).get().messages;
assertThat(messages).hasSize(3);
- assertThat(Iterables.getLast(messages).message).isEqualTo("Patch Set 1:\n\nTest Message");
+ assertThat(Iterables.getLast(messages).message).isEqualTo("Patch Set 1:\n\n(1 comment)");
assertThat(Iterables.getLast(messages).tag).isEqualTo("mailMessageId=some id");
+ // Assert comment
+ List<CommentInfo> comments = gApi.changes().id(changeId).current().commentsAsList();
+ assertThat(comments).hasSize(3);
+ assertThat(comments.get(0).path).isEqualTo(PATCHSET_LEVEL);
+ assertThat(comments.get(0).message).isEqualTo("Test Message");
+ assertThat(comments.get(0).tag).isEqualTo("mailMessageId=some id");
+ assertThat(comments.get(0).parent).isNull();
+ assertThat(comments.get(0).side).isNull();
+ assertThat(comments.get(0).line).isNull();
+ assertThat(comments.get(0).parent).isNull();
+ assertThat(comments.get(0).inReplyTo).isNull();
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java b/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
index 64ad900..277c0e6 100644
--- a/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/notedb/ExternalIdNotesUpsertPreprocessorIT.java
@@ -24,9 +24,9 @@
import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.server.ServerInitiated;
-import com.google.gerrit.server.account.Accounts;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdUpsertPreprocessor;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -50,7 +50,7 @@
@Inject private Sequences sequences;
@Inject private @ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider;
@Inject private ExternalIdNotes.Factory extIdNotesFactory;
- @Inject private Accounts accounts;
+ @Inject private ExternalIdFactory extIdFactory;
public static class Module extends AbstractModule {
@Override
@@ -72,7 +72,7 @@
@Test
public void insertAccount() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId));
assertThat(testPreprocessor.upserted).containsExactly(extId);
}
@@ -80,8 +80,8 @@
@Test
public void replaceByKeys() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar1", id);
- ExternalId extId2 = ExternalId.create("foo", "bar2", id);
+ ExternalId extId1 = extIdFactory.create("foo", "bar1", id);
+ ExternalId extId2 = extIdFactory.create("foo", "bar2", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -97,7 +97,7 @@
@Test
public void insert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
@@ -111,7 +111,7 @@
@Test
public void upsert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
try (Repository allUsersRepo = repoManager.openRepository(allUsers);
MetaDataUpdate md = metaDataUpdateFactory.create(allUsers)) {
@@ -125,8 +125,8 @@
@Test
public void replace() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar1", id);
- ExternalId extId2 = ExternalId.create("foo", "bar2", id);
+ ExternalId extId1 = extIdFactory.create("foo", "bar1", id);
+ ExternalId extId2 = extIdFactory.create("foo", "bar2", id);
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -142,8 +142,8 @@
@Test
public void replace_viaAccountsUpdate() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar", id, "email1@foo", "hash");
- ExternalId extId2 = ExternalId.create("foo", "bar", id, "email2@foo", "hash");
+ ExternalId extId1 = extIdFactory.create("foo", "bar", id, "email1@foo", "hash");
+ ExternalId extId2 = extIdFactory.create("foo", "bar", id, "email2@foo", "hash");
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
testPreprocessor.reset();
@@ -154,7 +154,7 @@
@Test
public void blockUpsert() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId = ExternalId.create("foo", "bar", id);
+ ExternalId extId = extIdFactory.create("foo", "bar", id);
testPreprocessor.throwException = true;
StorageException e =
assertThrows(
@@ -167,8 +167,8 @@
@Test
public void blockUpsert_replace() throws Exception {
Account.Id id = Account.id(sequences.nextAccountId());
- ExternalId extId1 = ExternalId.create("foo", "bar", id, "email1@foo", "hash");
- ExternalId extId2 = ExternalId.create("foo", "bar", id, "email2@foo", "hash");
+ ExternalId extId1 = extIdFactory.create("foo", "bar", id, "email1@foo", "hash");
+ ExternalId extId2 = extIdFactory.create("foo", "bar", id, "email2@foo", "hash");
accountsUpdateProvider.get().insert("test", id, u -> u.addExternalId(extId1));
assertThat(accounts.get(id).get().externalIds()).containsExactly(extId1);
diff --git a/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java b/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
index 9e4907c..46687e3 100644
--- a/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/permissions/ExternalUserPermissionIT.java
@@ -44,7 +44,7 @@
import com.google.gerrit.server.PropertyMap;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupMembership;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
@@ -70,6 +70,7 @@
@Inject private ChangeNotes.Factory changeNotesFactory;
@Inject private ExternalUser.Factory externalUserFactory;
@Inject private GroupOperations groupOperations;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
@Before
public void setUp() {
@@ -295,7 +296,7 @@
ExternalUser createUserInGroup(String userId, String groupId) {
return externalUserFactory.create(
ImmutableSet.of(),
- ImmutableSet.of(ExternalId.Key.parse("company-auth:" + groupId + "-" + userId)),
+ ImmutableSet.of(externalIdKeyFactory.parse("company-auth:" + groupId + "-" + userId)),
PropertyMap.EMPTY);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
index 33276e7..ba86976 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/ProjectWatchIT.java
@@ -16,9 +16,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
-import static com.google.gerrit.server.StarredChangesUtil.IGNORE_LABEL;
-import com.google.common.collect.ImmutableSet;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.NoHttpd;
import com.google.gerrit.acceptance.PushOneCommit;
@@ -32,7 +30,6 @@
import com.google.gerrit.entities.Permission;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.api.changes.ReviewInput;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.common.GroupInfo;
import com.google.gerrit.testing.FakeEmailSender.Message;
import com.google.inject.Inject;
@@ -470,7 +467,7 @@
// ignore the change
requestScopeOperations.setApiUser(user.id());
- gApi.accounts().self().setStars(r.getChangeId(), new StarsInput(ImmutableSet.of(IGNORE_LABEL)));
+ gApi.changes().id(r.getChangeId()).ignore(true);
sender.clear();
diff --git a/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsEvaluatorIT.java b/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsEvaluatorIT.java
index 9e85558..6e19c39 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsEvaluatorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/SubmitRequirementsEvaluatorIT.java
@@ -116,7 +116,7 @@
/* submittabilityExpr= */ "message:\"Fix bug\"",
/* overrideExpr= */ "");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.NOT_APPLICABLE);
}
@@ -128,7 +128,7 @@
/* submittabilityExpr= */ "message:\"Fix a bug\"",
/* overrideExpr= */ "");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.SATISFIED);
}
@@ -141,7 +141,7 @@
/* submittabilityExpr= */ "label:\"code-review=+2\"",
/* overrideExpr= */ "");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.UNSATISFIED);
assertThat(result.submittabilityExpressionResult().failingAtoms())
.containsExactly("label:\"code-review=+2\"");
@@ -163,7 +163,7 @@
/* submittabilityExpr= */ "label:\"code-review=+2\"",
/* overrideExpr= */ "label:\"build-cop-override=+1\"");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.OVERRIDDEN);
}
@@ -178,7 +178,7 @@
/* submittabilityExpr= */ "label:\"code-review=+2\"",
/* overrideExpr= */ "label:\"build-cop-override=+1\"");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.ERROR);
assertThat(result.applicabilityExpressionResult().get().errorMessage().get())
.isEqualTo("Unsupported operator invalid_field:invalid_value");
@@ -195,7 +195,7 @@
/* submittabilityExpr= */ "invalid_field:invalid_value",
/* overrideExpr= */ "label:\"build-cop-override=+1\"");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.ERROR);
assertThat(result.submittabilityExpressionResult().errorMessage().get())
.isEqualTo("Unsupported operator invalid_field:invalid_value");
@@ -209,7 +209,7 @@
/* submittabilityExpr= */ "label:\"code-review=+2\"",
/* overrideExpr= */ "invalid_field:invalid_value");
- SubmitRequirementResult result = evaluator.evaluate(sr, changeData);
+ SubmitRequirementResult result = evaluator.evaluateRequirement(sr, changeData);
assertThat(result.status()).isEqualTo(SubmitRequirementResult.Status.ERROR);
assertThat(result.overrideExpressionResult().get().errorMessage().get())
.isEqualTo("Unsupported operator invalid_field:invalid_value");
diff --git a/javatests/com/google/gerrit/acceptance/server/query/ApprovalQueryIT.java b/javatests/com/google/gerrit/acceptance/server/query/ApprovalQueryIT.java
index 9392219..b4d9558 100644
--- a/javatests/com/google/gerrit/acceptance/server/query/ApprovalQueryIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/query/ApprovalQueryIT.java
@@ -269,6 +269,7 @@
.key(PatchSetApproval.key(psId, approver, LabelId.create("Code-Review")))
.value(value)
.build();
- return ApprovalContext.create(changeNotes, approval, newPsId, changeKind);
+ return ApprovalContext.create(
+ changeNotes, approval, changeNotes.getPatchSets().get(newPsId), changeKind);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
index f866fff..3b38bad 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/AbstractIndexTests.java
@@ -38,7 +38,6 @@
public abstract class AbstractIndexTests extends AbstractDaemonTest {
@Inject private ExtensionRegistry extensionRegistry;
- /** @param injector injector */
public void configureIndex(Injector injector) {}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java b/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java
new file mode 100644
index 0000000..a82876e
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/ssh/SetAccountIT.java
@@ -0,0 +1,93 @@
+// 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.ssh;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
+
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.acceptance.NoHttpd;
+import com.google.gerrit.acceptance.TestAccount;
+import com.google.gerrit.acceptance.UseSsh;
+import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
+import com.google.gerrit.common.data.GlobalCapability;
+import com.google.gerrit.server.account.externalids.ExternalIds;
+import com.google.inject.Inject;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+@UseSsh
+@NoHttpd
+public class SetAccountIT extends AbstractDaemonTest {
+ @Inject private ExternalIds externalIds;
+ @Inject private ProjectOperations projectOperations;
+
+ @Test
+ public void setAccount_deleteExternalId_all() throws Exception {
+ TestAccount testAccount = accountCreator.create("user1", "user1@example.com", null, null);
+ adminSshSession.exec("gerrit set-account --delete-external-id ALL user1");
+ adminSshSession.assertSuccess();
+ assertThat(externalIds.byAccount(testAccount.id()).isEmpty()).isTrue();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_single() throws Exception {
+ TestAccount testAccount = accountCreator.create("user2", "user2@example.com", null, null);
+ List<String> extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user2")).isTrue();
+ assertThat(extIdKeys.contains("mailto:user2@example.com")).isTrue();
+ adminSshSession.exec("gerrit set-account --delete-external-id username:user2 user2");
+ adminSshSession.assertSuccess();
+ extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isFalse();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isFalse();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_multiple() throws Exception {
+ TestAccount testAccount = accountCreator.create("user3", "user3@example.com", null, null);
+ List<String> extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isTrue();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isTrue();
+ adminSshSession.exec(
+ "gerrit set-account --delete-external-id username:user3 --delete-external-id mailto:user3@example.com user3");
+ adminSshSession.assertSuccess();
+ extIdKeys = getExternalIdKeys(testAccount);
+ assertThat(extIdKeys.contains("username:user3")).isFalse();
+ assertThat(extIdKeys.contains("mailto:user3@example.com")).isFalse();
+ }
+
+ @Test
+ public void setAccount_deleteExternalId_byUser() throws Exception {
+ userSshSession.exec("gerrit set-account --delete-external-id mailto:admin@example.com admin");
+ userSshSession.assertFailure();
+ projectOperations
+ .allProjectsForUpdate()
+ .add(allowCapability(GlobalCapability.MODIFY_ACCOUNT).group(REGISTERED_USERS))
+ .update();
+ userSshSession.exec("gerrit set-account --delete-external-id mailto:admin@example.com admin");
+ userSshSession.assertSuccess();
+ userSshSession.exec("gerrit set-account --delete-external-id username:admin admin");
+ userSshSession.assertFailure();
+ }
+
+ private List<String> getExternalIdKeys(TestAccount account) throws Exception {
+ return externalIds.byAccount(account.id()).stream()
+ .map(e -> e.key().get())
+ .collect(Collectors.toList());
+ }
+}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/SshCancellationIT.java b/javatests/com/google/gerrit/acceptance/ssh/SshCancellationIT.java
index d08e219..e21cb26 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/SshCancellationIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/SshCancellationIT.java
@@ -122,7 +122,7 @@
@Test
public void abortIfClientProvidedDeadlineExceeded() throws Exception {
adminSshSession.exec("gerrit create-project --deadline 1ms " + name("new"));
- adminSshSession.assertFailure("Client Provided Deadline Exceeded (timeout=1ms)");
+ adminSshSession.assertFailure("Client Provided Deadline Exceeded (client.timeout=1ms)");
}
@Test
@@ -149,17 +149,18 @@
adminSshSession.assertSuccess();
}
+ @Test
@GerritConfig(name = "deadline.default.timeout", value = "1ms")
public void abortIfServerDeadlineExceeded() throws Exception {
adminSshSession.exec("gerrit create-project " + name("new"));
- adminSshSession.assertFailure("Server Deadline Exceeded (timeout=1ms)");
+ adminSshSession.assertFailure("Server Deadline Exceeded (default.timeout=1ms)");
}
@Test
@GerritConfig(name = "deadline.default.timeout", value = "1ms")
public void clientProvidedDeadlineOverridesServerDeadline() throws Exception {
adminSshSession.exec("gerrit create-project --deadline 2ms " + name("new"));
- adminSshSession.assertFailure("Client Provided Deadline Exceeded (timeout=2ms)");
+ adminSshSession.assertFailure("Client Provided Deadline Exceeded (client.timeout=2ms)");
}
@Test
diff --git a/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java b/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
index 7a61626..0883033 100644
--- a/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
+++ b/javatests/com/google/gerrit/auth/ldap/LdapRealmTest.java
@@ -30,6 +30,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.entities.AccountGroup;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
@@ -44,6 +45,7 @@
public final class LdapRealmTest {
@Inject private LdapRealm ldapRealm = null;
+ @Inject private ExternalIdFactory externalIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -67,7 +69,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return externalIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java b/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
index 1af78e3..3ec6f28 100644
--- a/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
+++ b/javatests/com/google/gerrit/auth/oauth/OAuthRealmTest.java
@@ -24,6 +24,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
@@ -34,6 +35,7 @@
public final class OAuthRealmTest {
@Inject private OAuthRealm oauthRealm = null;
+ @Inject private ExternalIdFactory externalIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -42,7 +44,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return externalIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java b/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
index 05b0ec0..f83409b 100644
--- a/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
+++ b/javatests/com/google/gerrit/auth/openid/OpenIdRealmTest.java
@@ -25,6 +25,7 @@
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.testing.InMemoryModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
@@ -35,6 +36,7 @@
public final class OpenIdRealmTest {
@Inject private OpenIdRealm openidRealm = null;
+ @Inject private ExternalIdFactory extIdFactory;
@Before
public void setUpInjector() throws Exception {
@@ -43,7 +45,7 @@
}
private ExternalId id(String scheme, String id) {
- return ExternalId.create(scheme, id, Account.id(1000));
+ return extIdFactory.create(scheme, id, Account.id(1000));
}
private boolean accountBelongsToRealm(ExternalId... ids) {
diff --git a/javatests/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverterTest.java b/javatests/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverterTest.java
index bf39ff8..d332f8a 100644
--- a/javatests/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverterTest.java
+++ b/javatests/com/google/gerrit/entities/converter/PatchSetApprovalProtoConverterTest.java
@@ -49,6 +49,7 @@
.tag("tag-21")
.realAccountId(Account.id(612))
.postSubmit(true)
+ .copied(true)
.build();
Entities.PatchSetApproval proto = protoConverter.toProto(patchSetApproval);
@@ -68,6 +69,7 @@
.setTag("tag-21")
.setRealAccountId(Entities.Account_Id.newBuilder().setId(612))
.setPostSubmit(true)
+ .setCopied(true)
.build();
assertThat(proto).isEqualTo(expectedProto);
}
@@ -99,6 +101,7 @@
.setGranted(987654L)
// This value can't be unset when our entity class is given.
.setPostSubmit(false)
+ .setCopied(false)
.build();
assertThat(proto).isEqualTo(expectedProto);
}
@@ -115,6 +118,7 @@
.tag("tag-21")
.realAccountId(Account.id(612))
.postSubmit(true)
+ .copied(true)
.build();
PatchSetApproval convertedPatchSetApproval =
@@ -162,6 +166,7 @@
assertThat(patchSetApproval.value()).isEqualTo(0);
assertThat(patchSetApproval.granted()).isEqualTo(new Timestamp(0));
assertThat(patchSetApproval.postSubmit()).isEqualTo(false);
+ assertThat(patchSetApproval.copied()).isEqualTo(false);
}
/** See {@link SerializedClassSubject} for background and what to do if this test fails. */
@@ -176,6 +181,7 @@
.put("tag", new TypeLiteral<Optional<String>>() {}.getType())
.put("realAccountId", Account.Id.class)
.put("postSubmit", boolean.class)
+ .put("copied", boolean.class)
.put("toBuilder", PatchSetApproval.Builder.class)
.build());
}
diff --git a/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java b/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
index 4352fe8..024e35e 100644
--- a/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
+++ b/javatests/com/google/gerrit/extensions/common/ChangeInfoDifferTest.java
@@ -58,6 +58,17 @@
}
@Test
+ public void getDiff_returnsOldAndNewChangeInfos() {
+ ChangeInfo oldChangeInfo = createChangeInfoWithTopic("topic");
+ ChangeInfo newChangeInfo = createChangeInfoWithTopic(oldChangeInfo.topic);
+
+ ChangeInfoDifference diff = ChangeInfoDiffer.getDifference(oldChangeInfo, newChangeInfo);
+
+ assertThat(diff.oldChangeInfo()).isEqualTo(oldChangeInfo);
+ assertThat(diff.newChangeInfo()).isEqualTo(newChangeInfo);
+ }
+
+ @Test
public void getDiff_givenUnchangedTopic_returnsNullTopics() {
ChangeInfo oldChangeInfo = createChangeInfoWithTopic("topic");
ChangeInfo newChangeInfo = createChangeInfoWithTopic(oldChangeInfo.topic);
diff --git a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
index 45b3419..05e9808 100644
--- a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
+++ b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
@@ -15,7 +15,6 @@
package com.google.gerrit.gpg;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.gerrit.gpg.GerritPublicKeyChecker.toExtIdKey;
import static com.google.gerrit.gpg.PublicKeyStore.keyToString;
import static com.google.gerrit.gpg.testing.TestKeys.validKeyWithSecondUserId;
import static com.google.gerrit.gpg.testing.TestTrustKeys.keyA;
@@ -39,6 +38,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.testing.InMemoryModule;
@@ -76,6 +76,10 @@
@Inject private ThreadLocalRequestContext requestContext;
+ @Inject private AuthRequest.Factory authRequestFactory;
+
+ @Inject private ExternalIdFactory externalIdFactory;
+
private LifecycleManager lifecycle;
private Account.Id userId;
private IdentifiedUser user;
@@ -101,7 +105,7 @@
lifecycle.start();
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
// Note: does not match any key in TestKeys.
accountsUpdateProvider
.get()
@@ -121,7 +125,7 @@
}
private IdentifiedUser addUser(String name) throws Exception {
- AuthRequest req = AuthRequest.forUser(name);
+ AuthRequest req = authRequestFactory.createForUser(name);
Account.Id id = accountManager.authenticate(req).getAccountId();
return userFactory.create(id);
}
@@ -202,16 +206,18 @@
reloadUser();
TestKey key = validKeyWithSecondUserId();
- PublicKeyChecker checker = checkerFactory.create(user, store).disableTrust();
+ GerritPublicKeyChecker checker =
+ (GerritPublicKeyChecker) checkerFactory.create(user, store).disableTrust();
assertProblems(
checker.check(key.getPublicKey()),
Status.BAD,
"No identities found for user; check http://test/settings#Identities");
- checker = checkerFactory.create().setStore(store).disableTrust();
+ checker = (GerritPublicKeyChecker) checkerFactory.create().setStore(store).disableTrust();
assertProblems(
checker.check(key.getPublicKey()), Status.BAD, "Key is not associated with any users");
- insertExtId(ExternalId.create(toExtIdKey(key.getPublicKey()), user.getAccountId()));
+ insertExtId(
+ externalIdFactory.create(checker.toExtIdKey(key.getPublicKey()), user.getAccountId()));
assertProblems(checker.check(key.getPublicKey()), Status.BAD, "No identities found for user");
}
@@ -362,13 +368,15 @@
private void add(PGPPublicKeyRing kr, IdentifiedUser user) throws Exception {
Account.Id id = user.getAccountId();
List<ExternalId> newExtIds = new ArrayList<>(2);
- newExtIds.add(ExternalId.create(toExtIdKey(kr.getPublicKey()), id));
+ GerritPublicKeyChecker checker =
+ (GerritPublicKeyChecker) checkerFactory.create(user, store).disableTrust();
+ newExtIds.add(externalIdFactory.create(checker.toExtIdKey(kr.getPublicKey()), id));
String userId = Iterators.getOnlyElement(kr.getPublicKey().getUserIDs(), null);
if (userId != null) {
String email = PushCertificateIdent.parse(userId).getEmailAddress();
assertThat(email).contains("@");
- newExtIds.add(ExternalId.createEmail(id, email));
+ newExtIds.add(externalIdFactory.createEmail(id, email));
}
store.add(kr);
@@ -401,7 +409,7 @@
}
private void addExternalId(String scheme, String id, String email) throws Exception {
- insertExtId(ExternalId.createWithEmail(scheme, id, user.getAccountId(), email));
+ insertExtId(externalIdFactory.createWithEmail(scheme, id, user.getAccountId(), email));
}
private void insertExtId(ExternalId extId) throws Exception {
diff --git a/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java b/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
index 2f0fafa..da6092b 100644
--- a/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
+++ b/javatests/com/google/gerrit/httpd/ProjectBasicAuthFilterTest.java
@@ -32,8 +32,12 @@
import com.google.gerrit.server.account.AccountException;
import com.google.gerrit.server.account.AccountManager;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.AuthResult;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
+import com.google.gerrit.server.account.externalids.PasswordVerifier;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.util.http.testutil.FakeHttpServletRequest;
import com.google.gerrit.util.http.testutil.FakeHttpServletResponse;
@@ -62,12 +66,6 @@
private static final String AUTH_PASSWORD = "jd123";
private static final String GERRIT_COOKIE_KEY = "GerritAccount";
private static final String AUTH_COOKIE_VALUE = "gerritcookie";
- private static final ExternalId AUTH_USER_PASSWORD_EXTERNAL_ID =
- ExternalId.createWithPassword(
- ExternalId.Key.create(ExternalId.SCHEME_USERNAME, AUTH_USER),
- AUTH_ACCOUNT_ID,
- null,
- AUTH_PASSWORD);
@Mock private DynamicItem<WebSession> webSessionItem;
@@ -93,14 +91,23 @@
private FakeHttpServletRequest req;
private HttpServletResponse res;
private AuthResult authSuccessful;
+ private ExternalIdFactory extIdFactory;
+ private ExternalIdKeyFactory extIdKeyFactory;
+ private PasswordVerifier pwdVerifier;
+ private AuthRequest.Factory authRequestFactory;
@Before
public void setUp() throws Exception {
req = new FakeHttpServletRequest("gerrit.example.com", 80, "", "");
res = new FakeHttpServletResponse();
+ extIdKeyFactory = new ExternalIdKeyFactory(new ExternalIdKeyFactory.ConfigImpl(authConfig));
+ extIdFactory = new ExternalIdFactory(extIdKeyFactory);
+ authRequestFactory = new AuthRequest.Factory(extIdKeyFactory);
+ pwdVerifier = new PasswordVerifier(extIdKeyFactory);
+
authSuccessful =
- new AuthResult(AUTH_ACCOUNT_ID, ExternalId.Key.create("username", AUTH_USER), false);
+ new AuthResult(AUTH_ACCOUNT_ID, extIdKeyFactory.create("username", AUTH_USER), false);
doReturn(Optional.of(accountState)).when(accountCache).getByUsername(AUTH_USER);
doReturn(Optional.of(accountState)).when(accountCache).get(AUTH_ACCOUNT_ID);
doReturn(account).when(accountState).account();
@@ -121,7 +128,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -136,7 +149,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -155,7 +174,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -175,7 +200,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -216,7 +247,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -235,7 +272,13 @@
doReturn(GitBasicAuthPolicy.LDAP).when(authConfig).getGitBasicAuthPolicy();
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
@@ -255,7 +298,13 @@
res.setStatus(HttpServletResponse.SC_OK);
ProjectBasicAuthFilter basicAuthFilter =
- new ProjectBasicAuthFilter(webSessionItem, accountCache, accountManager, authConfig);
+ new ProjectBasicAuthFilter(
+ webSessionItem,
+ accountCache,
+ accountManager,
+ authConfig,
+ authRequestFactory,
+ pwdVerifier);
basicAuthFilter.doFilter(req, res, chain);
}
@@ -278,9 +327,13 @@
}
private void initMockedUsernamePasswordExternalId() {
- doReturn(ImmutableSet.builder().add(AUTH_USER_PASSWORD_EXTERNAL_ID).build())
- .when(accountState)
- .externalIds();
+ ExternalId extId =
+ extIdFactory.createWithPassword(
+ extIdKeyFactory.create(ExternalId.SCHEME_USERNAME, AUTH_USER),
+ AUTH_ACCOUNT_ID,
+ null,
+ AUTH_PASSWORD);
+ doReturn(ImmutableSet.builder().add(extId).build()).when(accountState).externalIds();
}
private void requestBasicAuth(FakeHttpServletRequest fakeReq) {
diff --git a/javatests/com/google/gerrit/mail/AbstractParserTest.java b/javatests/com/google/gerrit/mail/AbstractParserTest.java
index b22b8ad..a2432a2 100644
--- a/javatests/com/google/gerrit/mail/AbstractParserTest.java
+++ b/javatests/com/google/gerrit/mail/AbstractParserTest.java
@@ -31,11 +31,11 @@
protected static final String CHANGE_URL =
"https://gerrit-review.googlesource.com/c/project/+/123";
- protected static void assertChangeMessage(String message, MailComment comment) {
+ protected static void assertPatchsetComment(String message, MailComment comment) {
assertThat(comment.fileName).isNull();
assertThat(comment.message).isEqualTo(message);
assertThat(comment.inReplyTo).isNull();
- assertThat(comment.type).isEqualTo(MailComment.CommentType.CHANGE_MESSAGE);
+ assertThat(comment.type).isEqualTo(MailComment.CommentType.PATCHSET_LEVEL);
}
protected static void assertInlineComment(
diff --git a/javatests/com/google/gerrit/mail/HtmlParserTest.java b/javatests/com/google/gerrit/mail/HtmlParserTest.java
index d661278..bb60fd8 100644
--- a/javatests/com/google/gerrit/mail/HtmlParserTest.java
+++ b/javatests/com/google/gerrit/mail/HtmlParserTest.java
@@ -35,7 +35,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, "");
assertThat(parsedComments).hasSize(1);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
}
@Test
@@ -56,7 +56,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, "");
assertThat(parsedComments).hasSize(1);
- assertChangeMessage(
+ assertPatchsetComment(
"Did you consider this: http://gerritcodereview.com", parsedComments.get(0));
}
@@ -77,7 +77,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertInlineComment("I have a comment on this.", parsedComments.get(1), comments.get(1));
assertInlineComment("Also have a comment here.", parsedComments.get(2), comments.get(4));
}
@@ -100,7 +100,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertInlineComment(
"How about [1]? This would help IMHO.\n\n[1] http://gerritcodereview.com",
parsedComments.get(1),
@@ -125,7 +125,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertFileComment("This is a nice file", parsedComments.get(1), comments.get(1).key.filename);
assertInlineComment("Also have a comment here.", parsedComments.get(2), comments.get(4));
}
@@ -168,7 +168,7 @@
List<MailComment> parsedComments = HtmlParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage(txtMessage, parsedComments.get(0));
+ assertPatchsetComment(txtMessage, parsedComments.get(0));
assertFileComment(txtMessage, parsedComments.get(1), comments.get(1).key.filename);
assertInlineComment(txtMessage, parsedComments.get(2), comments.get(4));
}
@@ -176,7 +176,6 @@
/**
* Create an html message body with the specified comments.
*
- * @param changeMessage
* @param c1 Comment in reply to first comment.
* @param c2 Comment in reply to second comment.
* @param c3 Comment in reply to third comment.
diff --git a/javatests/com/google/gerrit/mail/TextParserTest.java b/javatests/com/google/gerrit/mail/TextParserTest.java
index f1d6179..d3e7447 100644
--- a/javatests/com/google/gerrit/mail/TextParserTest.java
+++ b/javatests/com/google/gerrit/mail/TextParserTest.java
@@ -43,7 +43,7 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(1);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
}
@Test
@@ -64,7 +64,7 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertInlineComment("I have a comment on this.", parsedComments.get(1), comments.get(1));
assertInlineComment("Also have a comment here.", parsedComments.get(2), comments.get(3));
}
@@ -87,7 +87,7 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertFileComment("This is a nice file", parsedComments.get(1), comments.get(1).key.filename);
assertInlineComment("Also have a comment here.", parsedComments.get(2), comments.get(3));
}
@@ -138,7 +138,7 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(3);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertFileComment("This is a nice file", parsedComments.get(1), comments.get(1).key.filename);
assertInlineComment("Also have a comment here.", parsedComments.get(2), comments.get(3));
}
@@ -161,7 +161,7 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), comments, CHANGE_URL);
assertThat(parsedComments).hasSize(2);
- assertChangeMessage("Looks good to me", parsedComments.get(0));
+ assertPatchsetComment("Looks good to me", parsedComments.get(0));
assertInlineComment("Comment in reply to file comment", parsedComments.get(1), comments.get(0));
}
@@ -174,14 +174,13 @@
List<MailComment> parsedComments = TextParser.parse(b.build(), defaultComments(), CHANGE_URL);
assertThat(parsedComments).hasSize(1);
- assertChangeMessage(
+ assertPatchsetComment(
"Nice change\n\nMy other comment on the same entity", parsedComments.get(0));
}
/**
* Create a plaintext message body with the specified comments.
*
- * @param changeMessage
* @param c1 Comment in reply to first inline comment.
* @param c2 Comment in reply to second inline comment.
* @param c3 Comment in reply to third inline comment.
diff --git a/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java b/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java
index e34b578..fd47567 100644
--- a/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java
+++ b/javatests/com/google/gerrit/pgm/init/api/AllProjectsConfigTest.java
@@ -17,6 +17,8 @@
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
+import com.google.gerrit.server.config.AllProjectsConfigProvider;
+import com.google.gerrit.server.config.FileBasedAllProjectsConfigProvider;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.securestore.testing.InMemorySecureStore;
import java.io.File;
@@ -76,8 +78,11 @@
InitFlags flags = new InitFlags(sitePaths, secureStore, ImmutableList.of(), false);
Section.Factory sections =
(name, subsection) -> new Section(flags, sitePaths, secureStore, ui, name, subsection);
+ AllProjectsConfigProvider configProvider = new FileBasedAllProjectsConfigProvider(sitePaths);
+
allProjectsConfig =
- new AllProjectsConfig(new AllProjectsNameOnInitProvider(sections), sitePaths, flags);
+ new AllProjectsConfig(
+ new AllProjectsNameOnInitProvider(sections), configProvider, sitePaths, flags);
}
@Test
diff --git a/javatests/com/google/gerrit/server/CancellationMetricsTest.java b/javatests/com/google/gerrit/server/RequestInfoTest.java
similarity index 93%
rename from javatests/com/google/gerrit/server/CancellationMetricsTest.java
rename to javatests/com/google/gerrit/server/RequestInfoTest.java
index b27d9d2..fafe856 100644
--- a/javatests/com/google/gerrit/server/CancellationMetricsTest.java
+++ b/javatests/com/google/gerrit/server/RequestInfoTest.java
@@ -18,7 +18,7 @@
import org.junit.Test;
-public class CancellationMetricsTest {
+public class RequestInfoTest {
@Test
public void redactRequestUri() throws Exception {
// test with valid request URIs
@@ -28,6 +28,7 @@
assertThat(redact("/changes/123")).isEqualTo("/changes/*");
assertThat(redact("/changes/123/detail")).isEqualTo("/changes/*/detail");
assertThat(redact("/changes/123/detail/")).isEqualTo("/changes/*/detail/");
+ assertThat(redact("/accounts/self/capabilities")).isEqualTo("/accounts/*/capabilities");
assertThat(redact("/foo/123/bar/567")).isEqualTo("/foo/*/bar/*");
assertThat(redact("/foo/123/bar/567/baz")).isEqualTo("/foo/*/bar/*/baz");
assertThat(redact("/foo/123/bar/567/baz/")).isEqualTo("/foo/*/bar/*/baz/");
@@ -51,6 +52,6 @@
}
public static String redact(String uri) {
- return CancellationMetrics.redactRequestUri(uri);
+ return RequestInfo.redactRequestUri(uri);
}
}
diff --git a/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java b/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
index 814df03..7d9db0b 100644
--- a/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
+++ b/javatests/com/google/gerrit/server/account/externalids/AllExternalIdsTest.java
@@ -26,11 +26,28 @@
import com.google.gerrit.server.cache.proto.Cache.AllExternalIdsProto;
import com.google.gerrit.server.cache.proto.Cache.AllExternalIdsProto.ExternalIdProto;
import com.google.inject.TypeLiteral;
+import java.lang.reflect.Type;
import java.util.Arrays;
import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Before;
import org.junit.Test;
public class AllExternalIdsTest {
+ private ExternalIdFactory externalIdFactory;
+
+ @Before
+ public void setUp() throws Exception {
+ externalIdFactory =
+ new ExternalIdFactory(
+ new ExternalIdKeyFactory(
+ new ExternalIdKeyFactory.Config() {
+ @Override
+ public boolean isUserNameCaseInsensitive() {
+ return false;
+ }
+ }));
+ }
+
@Test
public void serializeEmptyExternalIds() throws Exception {
assertRoundTrip(allExternalIds(), AllExternalIdsProto.getDefaultInstance());
@@ -42,10 +59,10 @@
Account.Id accountId2 = Account.id(1002);
assertRoundTrip(
allExternalIds(
- ExternalId.create("scheme1", "id1", accountId1),
- ExternalId.create("scheme2", "id2", accountId1),
- ExternalId.create("scheme2", "id3", accountId2),
- ExternalId.create("scheme3", "id4", accountId2)),
+ externalIdFactory.create("scheme1", "id1", accountId1),
+ externalIdFactory.create("scheme2", "id2", accountId1),
+ externalIdFactory.create("scheme2", "id3", accountId2),
+ externalIdFactory.create("scheme3", "id4", accountId2)),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder().setKey("scheme1:id1").setAccountId(1001).build())
@@ -61,7 +78,7 @@
@Test
public void serializeExternalIdWithEmail() throws Exception {
assertRoundTrip(
- allExternalIds(ExternalId.createEmail(Account.id(1001), "foo@example.com")),
+ allExternalIds(externalIdFactory.createEmail(Account.id(1001), "foo@example.com")),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder()
@@ -75,7 +92,7 @@
public void serializeExternalIdWithPassword() throws Exception {
assertRoundTrip(
allExternalIds(
- ExternalId.create("scheme", "id", Account.id(1001), null, "hashed password")),
+ externalIdFactory.create("scheme", "id", Account.id(1001), null, "hashed password")),
AllExternalIdsProto.newBuilder()
.addExternalId(
ExternalIdProto.newBuilder()
@@ -89,8 +106,8 @@
public void serializeExternalIdWithBlobId() throws Exception {
assertRoundTrip(
allExternalIds(
- ExternalId.create(
- ExternalId.create("scheme", "id", Account.id(1001)),
+ externalIdFactory.create(
+ externalIdFactory.create("scheme", "id", Account.id(1001)),
ObjectId.fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"))),
AllExternalIdsProto.newBuilder()
.addExternalId(
@@ -121,12 +138,14 @@
public void externalIdMethods() {
assertThatSerializedClass(ExternalId.class)
.hasAutoValueMethods(
- ImmutableMap.of(
- "key", ExternalId.Key.class,
- "accountId", Account.Id.class,
- "email", String.class,
- "password", String.class,
- "blobId", ObjectId.class));
+ ImmutableMap.<String, Type>builder()
+ .put("key", ExternalId.Key.class)
+ .put("accountId", Account.Id.class)
+ .put("isCaseInsensitive", boolean.class)
+ .put("email", String.class)
+ .put("password", String.class)
+ .put("blobId", ObjectId.class)
+ .build());
}
private static AllExternalIds allExternalIds(ExternalId... externalIds) {
diff --git a/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
index 5717e78..4f8c559 100644
--- a/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
+++ b/javatests/com/google/gerrit/server/account/externalids/ExternalIDCacheLoaderTest.java
@@ -57,11 +57,23 @@
private ExternalIdReader externalIdReader;
private ExternalIdReader externalIdReaderSpy;
+ private ExternalIdFactory externalIdFactory;
+
@Before
public void setUp() throws Exception {
+ externalIdFactory =
+ new ExternalIdFactory(
+ new ExternalIdKeyFactory(
+ new ExternalIdKeyFactory.Config() {
+ @Override
+ public boolean isUserNameCaseInsensitive() {
+ return false;
+ }
+ }));
externalIdCache = CacheBuilder.newBuilder().build();
repoManager.createRepository(ALL_USERS).close();
- externalIdReader = new ExternalIdReader(repoManager, ALL_USERS, new DisabledMetricMaker());
+ externalIdReader =
+ new ExternalIdReader(repoManager, ALL_USERS, new DisabledMetricMaker(), externalIdFactory);
externalIdReaderSpy = Mockito.spy(externalIdReader);
loader = createLoader(true);
}
@@ -151,7 +163,8 @@
ObjectId head =
modifyExternalId(
externalId(1, 1),
- ExternalId.create("fooschema", "bar1", Account.id(1), "foo@bar.com", "password"));
+ externalIdFactory.create(
+ "fooschema", "bar1", Account.id(1), "foo@bar.com", "password"));
assertThat(allFromGit(head).byAccount().size()).isEqualTo(1);
externalIdCache.put(firstState, allFromGit(firstState));
@@ -212,7 +225,8 @@
externalIdReaderSpy,
Providers.of(externalIdCache),
new DisabledMetricMaker(),
- cfg);
+ cfg,
+ externalIdFactory);
}
private AllExternalIds allFromGit(ObjectId revision) throws Exception {
@@ -256,13 +270,14 @@
}
private ExternalId externalId(int key, int accountId) {
- return ExternalId.create("fooschema", "bar" + key, Account.id(accountId));
+ return externalIdFactory.create("fooschema", "bar" + key, Account.id(accountId));
}
private ObjectId performExternalIdUpdate(Consumer<ExternalIdNotes> update) throws Exception {
try (Repository repo = repoManager.openRepository(ALL_USERS)) {
PersonIdent updater = new PersonIdent("Foo bar", "foo@bar.com");
- ExternalIdNotes extIdNotes = ExternalIdNotes.loadNoCacheUpdate(ALL_USERS, repo);
+ ExternalIdNotes extIdNotes =
+ ExternalIdNotes.loadNoCacheUpdate(ALL_USERS, repo, externalIdFactory);
update.accept(extIdNotes);
try (MetaDataUpdate metaDataUpdate =
new MetaDataUpdate(GitReferenceUpdated.DISABLED, null, repo)) {
diff --git a/javatests/com/google/gerrit/server/change/IncludedInResolverTest.java b/javatests/com/google/gerrit/server/change/IncludedInResolverTest.java
index 19c479d..b69a894 100644
--- a/javatests/com/google/gerrit/server/change/IncludedInResolverTest.java
+++ b/javatests/com/google/gerrit/server/change/IncludedInResolverTest.java
@@ -17,9 +17,13 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.entities.RefNames.REFS_TAGS;
+import com.google.common.truth.Correspondence;
+import com.google.gerrit.truth.NullAwareCorrespondence;
import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.revwalk.RevTag;
@@ -112,8 +116,12 @@
IncludedInResolver.Result detail = resolve(commit_v2_5);
// Check that only tags and branches which refer the tip are returned
- assertThat(detail.tags()).containsExactly(TAG_2_5, TAG_2_5_ANNOTATED, TAG_2_5_ANNOTATED_TWICE);
- assertThat(detail.branches()).containsExactly(BRANCH_2_5);
+ assertThat(detail.tags())
+ .comparingElementsUsing(hasShortName())
+ .containsExactly(TAG_2_5, TAG_2_5_ANNOTATED, TAG_2_5_ANNOTATED_TWICE);
+ assertThat(detail.branches())
+ .comparingElementsUsing(hasShortName())
+ .containsExactly(BRANCH_2_5);
}
@Test
@@ -123,6 +131,7 @@
// Check whether all tags and branches are returned
assertThat(detail.tags())
+ .comparingElementsUsing(hasShortName())
.containsExactly(
TAG_1_0,
TAG_1_0_1,
@@ -133,6 +142,7 @@
TAG_2_5_ANNOTATED,
TAG_2_5_ANNOTATED_TWICE);
assertThat(detail.branches())
+ .comparingElementsUsing(hasShortName())
.containsExactly(BRANCH_MASTER, BRANCH_1_0, BRANCH_1_3, BRANCH_2_0, BRANCH_2_5);
}
@@ -143,8 +153,11 @@
// Check whether all succeeding tags and branches are returned
assertThat(detail.tags())
+ .comparingElementsUsing(hasShortName())
.containsExactly(TAG_1_3, TAG_2_5, TAG_2_5_ANNOTATED, TAG_2_5_ANNOTATED_TWICE);
- assertThat(detail.branches()).containsExactly(BRANCH_1_3, BRANCH_2_5);
+ assertThat(detail.branches())
+ .comparingElementsUsing(hasShortName())
+ .containsExactly(BRANCH_1_3, BRANCH_2_5);
}
private IncludedInResolver.Result resolve(RevCommit commit) throws Exception {
@@ -154,4 +167,9 @@
private RevTag tag(String name, RevObject dest) throws Exception {
return tr.update(REFS_TAGS + name, tr.tag(name, dest));
}
+
+ private static Correspondence<Ref, String> hasShortName() {
+ return NullAwareCorrespondence.transforming(
+ ref -> Repository.shortenRefName(ref.getName()), "has short name");
+ }
}
diff --git a/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java b/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
index cd28ac4..5e3be9a 100644
--- a/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
+++ b/javatests/com/google/gerrit/server/change/LabelNormalizerTest.java
@@ -71,6 +71,7 @@
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private GerritApi gApi;
@Inject private ProjectOperations projectOperations;
+ @Inject private AuthRequest.Factory authRequestFactory;
private LifecycleManager lifecycle;
private Account.Id userId;
@@ -87,7 +88,7 @@
lifecycle.start();
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
user = userFactory.create(userId);
requestContext.setContext(() -> user);
diff --git a/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
index 7832bec..6b8177e 100644
--- a/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/GitRepositoryManagerTest.java
@@ -36,6 +36,12 @@
}
private static class TestGitRepositoryManager implements GitRepositoryManager {
+
+ @Override
+ public Status getRepositoryStatus(NameKey name) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
@Override
public Repository openRepository(NameKey name) {
throw new UnsupportedOperationException("Not implemented");
diff --git a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
index febb142..12130ea 100644
--- a/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
+++ b/javatests/com/google/gerrit/server/git/LocalDiskRepositoryManagerTest.java
@@ -20,6 +20,7 @@
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.git.GitRepositoryManager.Status;
import com.google.gerrit.server.ioutil.HostPlatform;
import java.io.IOException;
import java.nio.file.Files;
@@ -67,6 +68,7 @@
try (Repository repo = repoManager.openRepository(projectA)) {
assertThat(repo).isNotNull();
}
+ assertThat(repoManager.getRepositoryStatus(projectA)).isEqualTo(Status.ACTIVE);
assertThat(repoManager.list()).containsExactly(projectA);
}
@@ -199,7 +201,7 @@
public void testProjectRecreation() throws Exception {
repoManager.createRepository(Project.nameKey("a"));
assertThrows(
- IllegalStateException.class, () -> repoManager.createRepository(Project.nameKey("a")));
+ RepositoryExistsException.class, () -> repoManager.createRepository(Project.nameKey("a")));
}
@Test
@@ -207,7 +209,8 @@
repoManager.createRepository(Project.nameKey("a"));
LocalDiskRepositoryManager newRepoManager = new LocalDiskRepositoryManager(site, cfg);
assertThrows(
- IllegalStateException.class, () -> newRepoManager.createRepository(Project.nameKey("a")));
+ RepositoryExistsException.class,
+ () -> newRepoManager.createRepository(Project.nameKey("a")));
}
@Test
@@ -221,6 +224,19 @@
}
@Test
+ public void testGetRepositoryStatusNameCaseMismatch() throws Exception {
+ assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
+ repoManager.createRepository(Project.nameKey("a"));
+ assertThat(repoManager.getRepositoryStatus(Project.nameKey("A"))).isEqualTo(Status.ACTIVE);
+ }
+
+ @Test
+ public void testGetRepositoryStatusNonExistent() throws Exception {
+ assertThat(repoManager.getRepositoryStatus(Project.nameKey("non-existent")))
+ .isEqualTo(Status.NON_EXISTENT);
+ }
+
+ @Test
public void testNameCaseMismatch() throws Exception {
assume().that(HostPlatform.isWin32() || HostPlatform.isMac()).isTrue();
repoManager.createRepository(Project.nameKey("a"));
@@ -272,6 +288,12 @@
}
@Test
+ public void testGetRepoStatusInvalidName() throws Exception {
+ assertThat(repoManager.getRepositoryStatus(Project.nameKey("project%?|<>A")))
+ .isEqualTo(Status.NON_EXISTENT);
+ }
+
+ @Test
public void list() throws Exception {
Project.NameKey projectA = Project.nameKey("projectA");
createRepository(repoManager.getBasePath(projectA), projectA.get());
diff --git a/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java b/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
index 92a5fbe..d16efc3 100644
--- a/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
+++ b/javatests/com/google/gerrit/server/index/account/AccountFieldTest.java
@@ -56,25 +56,33 @@
.build();
ExternalId extId1 =
ExternalId.create(
- ExternalId.Key.create(ExternalId.SCHEME_MAILTO, "foo.bar@example.com"),
+ ExternalId.Key.create(ExternalId.SCHEME_MAILTO, "foo.bar@example.com", false),
id,
"foo.bar@example.com",
null,
ObjectId.fromString("1b9a0cf038ea38a0ab08617c39aa8e28413a27ca"));
ExternalId extId2 =
ExternalId.create(
- ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "foo"),
+ ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "foo", false),
id,
null,
"secret",
ObjectId.fromString("5b3a73dc9a668a5b89b5f049225261e3e3291d1a"));
+ ExternalId extId3 =
+ ExternalId.create(
+ ExternalId.Key.create(ExternalId.SCHEME_USERNAME, "Bar", true),
+ id,
+ null,
+ "secret",
+ ObjectId.fromString("483ea804e84282e15ddcdd1d15a797eb4796a760"));
List<String> values =
toStrings(
AccountField.EXTERNAL_ID_STATE.get(
- AccountState.forAccount(account, ImmutableSet.of(extId1, extId2))));
+ AccountState.forAccount(account, ImmutableSet.of(extId1, extId2, extId3))));
String expectedValue1 = extId1.key().sha1().name() + ":" + extId1.blobId().name();
String expectedValue2 = extId2.key().sha1().name() + ":" + extId2.blobId().name();
- assertThat(values).containsExactly(expectedValue1, expectedValue2);
+ String expectedValue3 = extId3.key().sha1().name() + ":" + extId3.blobId().name();
+ assertThat(values).containsExactly(expectedValue1, expectedValue2, expectedValue3);
}
private List<String> toStrings(Iterable<byte[]> values) {
diff --git a/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java b/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java
index 521af2f..66a98e8 100644
--- a/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java
+++ b/javatests/com/google/gerrit/server/index/change/FakeQueryBuilder.java
@@ -55,6 +55,7 @@
null,
new Config(),
null,
+ null,
null));
}
diff --git a/javatests/com/google/gerrit/server/logging/PerformanceLogContextTest.java b/javatests/com/google/gerrit/server/logging/PerformanceLogContextTest.java
index ed4325d..fefa066 100644
--- a/javatests/com/google/gerrit/server/logging/PerformanceLogContextTest.java
+++ b/javatests/com/google/gerrit/server/logging/PerformanceLogContextTest.java
@@ -34,6 +34,7 @@
import com.google.inject.Injector;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jgit.lib.Config;
import org.junit.After;
import org.junit.Before;
@@ -110,9 +111,10 @@
@Test
public void
- traceTimersInsidePerformanceLogContextDoNotCreatePerformanceLogIfNoPerformanceLoggers() {
+ traceTimersInsidePerformanceLogContextDoNotCreatePerformanceLogIfNoPerformanceLoggers()
+ throws Exception {
// Remove test performance logger so that there are no registered performance loggers.
- performanceLoggerRegistrationHandle.remove();
+ removeAllPerformanceLoggers();
assertThat(LoggingContext.getInstance().isPerformanceLogging()).isFalse();
assertThat(LoggingContext.getInstance().getPerformanceLogRecords()).isEmpty();
@@ -277,9 +279,10 @@
@Test
public void
- timerMetricssInsidePerformanceLogContextDoNotCreatePerformanceLogIfNoPerformanceLoggers() {
- // Remove test performance logger so that there are no registered performance loggers.
- performanceLoggerRegistrationHandle.remove();
+ timerMetricssInsidePerformanceLogContextDoNotCreatePerformanceLogIfNoPerformanceLoggers()
+ throws Exception {
+ // Remove all performance loggers so that there are no registered performance loggers.
+ removeAllPerformanceLoggers();
assertThat(LoggingContext.getInstance().isPerformanceLogging()).isFalse();
assertThat(LoggingContext.getInstance().getPerformanceLogRecords()).isEmpty();
@@ -369,6 +372,12 @@
}
}
+ private void removeAllPerformanceLoggers() throws Exception {
+ java.lang.reflect.Field itemsField = DynamicSet.class.getDeclaredField("items");
+ itemsField.setAccessible(true);
+ ((CopyOnWriteArrayList<?>) itemsField.get(performanceLoggers)).clear();
+ }
+
@AutoValue
abstract static class PerformanceLogEntry {
static PerformanceLogEntry create(String operation, Metadata metadata) {
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
index 6a32fa1..dc9b9cd 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesParserTest.java
@@ -153,6 +153,43 @@
}
@Test
+ public void parseCopiedApproval() throws Exception {
+ assertParseSucceeds(
+ "Update change\n"
+ + "\n"
+ + "Branch: refs/heads/master\n"
+ + "Change-id: I577fb248e474018276351785930358ec0450e9f7\n"
+ + "Patch-set: 1\n"
+ + "Copied-Label: Label1=+1 Account <1@gerrit>,Other Account <2@Gerrit>\n"
+ + "Copied-Label: Label2=+1 Account <1@gerrit>\n"
+ + "Copied-Label: Label3=+1 Account <1@gerrit>,Other Account <2@Gerrit> :\"tag\"\n"
+ + "Copied-Label: Label4=+1 Account <1@Gerrit> :\"tag with characters %^#@^( *::!\"\n"
+ + "Subject: This is a test change\n");
+ assertParseSucceeds(
+ "Update change\n"
+ + "\n"
+ + "Branch: refs/heads/master\n"
+ + "Change-id: I577fb248e474018276351785930358ec0450e9f7\n"
+ + "Patch-set: 1\n"
+ + "Label: -Label1\n"
+ + "Label: -Label4 Account <1@gerrit>\n"
+ + "Subject: This is a test change\n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: Label1=X\n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: Label1 = 1\n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: X+Y\n");
+ assertParseFails(
+ "Update change\n\nPatch-set: 1\nCopied-Label: Label1 Other Account <2@gerrit>\n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: -Label!1\n");
+ assertParseFails(
+ "Update change\n\nPatch-set: 1\nCopied-Label: -Label!1 Other Account <2@gerrit>\n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: -Label1\n");
+ assertParseFails(
+ "Update change\n\nPatch-set: 1\nCopied-Label: Label1 Other Account <2@gerrit>,Other "
+ + "Account <2@gerrit>,Other Account <2@gerrit> \n");
+ assertParseFails("Update change\n\nPatch-set: 1\nCopied-Label: Label1 non-user\n");
+ }
+
+ @Test
public void parseSubmitRecords() throws Exception {
assertParseSucceeds(
"Update change\n"
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
index 209d880..52eaf11 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesStateTest.java
@@ -375,6 +375,7 @@
PatchSetApproval.key(
PatchSet.id(ID, 1), Account.id(2001), LabelId.create(LabelId.CODE_REVIEW)))
.value(1)
+ .tag("tag")
.granted(new Timestamp(1212L))
.build();
Entities.PatchSetApproval psa1 = PatchSetApprovalProtoConverter.INSTANCE.toProto(a1);
@@ -386,11 +387,13 @@
PatchSetApproval.key(
PatchSet.id(ID, 1), Account.id(2002), LabelId.create(LabelId.VERIFIED)))
.value(-1)
+ .tag("tag")
+ .copied(true)
.granted(new Timestamp(3434L))
.build();
Entities.PatchSetApproval psa2 = PatchSetApprovalProtoConverter.INSTANCE.toProto(a2);
ByteString a2Bytes = Protos.toByteString(psa2);
- assertThat(a2Bytes.size()).isEqualTo(49);
+ assertThat(a2Bytes.size()).isEqualTo(56);
assertThat(a2Bytes).isNotEqualTo(a1Bytes);
assertRoundTrip(
@@ -684,6 +687,7 @@
.submitRequirementsResult(
ImmutableList.of(
SubmitRequirementResult.builder()
+ .legacy(true)
.patchSetCommitId(
ObjectId.fromString("26e50c7d315a33a13e5cc00902781fa876bc36cd"))
.submitRequirement(
@@ -713,6 +717,7 @@
newProtoBuilder()
.addSubmitRequirementResult(
SubmitRequirementResultProto.newBuilder()
+ .setLegacy(true)
.setCommit(
ObjectIdConverter.create()
.toByteString(
@@ -978,6 +983,7 @@
.put("tag", new TypeLiteral<Optional<String>>() {}.getType())
.put("realAccountId", Account.Id.class)
.put("postSubmit", boolean.class)
+ .put("copied", boolean.class)
.put("toBuilder", PatchSetApproval.Builder.class)
.build());
}
@@ -1035,6 +1041,8 @@
assertThatSerializedClass(SubmitRecord.class)
.hasFields(
ImmutableMap.of(
+ "ruleName",
+ new TypeLiteral<String>() {}.getType(),
"status",
SubmitRecord.Status.class,
"labels",
@@ -1065,7 +1073,7 @@
.setChangeId(ID.get())
.setMergedOnMillis(234567L)
.setHasMergedOn(true)
- .setColumns(colsProto.toBuilder())
+ .setColumns(colsProto)
.build());
}
@@ -1128,7 +1136,7 @@
.setChangeId(ID.get())
.setServerId(DEFAULT_SERVER_ID)
.setHasServerId(true)
- .setColumns(colsProto.toBuilder())
+ .setColumns(colsProto)
.build());
}
diff --git a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
index 9c2e9a9..c524c94 100644
--- a/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
+++ b/javatests/com/google/gerrit/server/notedb/ChangeNotesTest.java
@@ -514,6 +514,184 @@
}
@Test
+ public void copiedApprovals() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.CODE_REVIEW)))
+ .value(1)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .tag("tag")
+ .realAccountId(otherUserId)
+ .build());
+ update.putApprovalFor(otherUserId, LabelId.CODE_REVIEW, (short) -1);
+ update.commit();
+
+ // Only the non copied approval is reachable by getApprovals.
+ ChangeNotes notes = newNotes(c);
+ PatchSetApproval approval =
+ Iterables.getOnlyElement(notes.getApprovals().get(c.currentPatchSetId()));
+ assertThat(approval.accountId()).isEqualTo(otherUser.getAccountId());
+ assertThat(approval.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(approval.value()).isEqualTo((short) -1);
+ assertThat(approval.copied()).isFalse();
+
+ // Get approvals with copied gets all of the approvals (including copied).
+ ImmutableList<PatchSetApproval> approvals =
+ notes.getApprovalsWithCopied().get(c.currentPatchSetId()).stream()
+ .sorted(comparing(a -> a.accountId().get()))
+ .collect(toImmutableList());
+ assertThat(approvals).hasSize(2);
+
+ PatchSetApproval copied = approvals.get(0);
+ assertThat(copied.accountId()).isEqualTo(changeOwner.getAccountId());
+ assertThat(copied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(copied.value()).isEqualTo((short) 1);
+ assertThat(copied.tag()).hasValue("tag");
+ assertThat(copied.accountId()).isEqualTo(changeOwner.getAccountId());
+ assertThat(copied.realAccountId()).isEqualTo(otherUserId);
+ assertThat(copied.copied()).isTrue();
+
+ PatchSetApproval nonCopied = approvals.get(1);
+ assertThat(nonCopied.accountId()).isEqualTo(otherUserId);
+ assertThat(nonCopied.realAccountId()).isEqualTo(otherUserId);
+ assertThat(nonCopied.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(nonCopied.value()).isEqualTo((short) -1);
+ }
+
+ @Test
+ public void copiedApprovalsCanBeRemoved() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.CODE_REVIEW)))
+ .value(1)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .build());
+ update.commit();
+
+ update.removeApproval(LabelId.CODE_REVIEW);
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ PatchSetApproval approval =
+ Iterables.getOnlyElement(notes.getApprovalsWithCopied().get(c.currentPatchSetId()));
+ assertThat(approval.accountId()).isEqualTo(changeOwner.getAccountId());
+ assertThat(approval.label()).isEqualTo(LabelId.CODE_REVIEW);
+ // The vote got removed since the latest patch-set only has one vote and it's "0". The copied
+ // approval will never have a "0" vote, but it can be overridden by a "0" vote of a
+ // non-copied approval.
+ assertThat(approval.value()).isEqualTo((short) 0);
+ assertThat(approval.copied()).isFalse();
+ }
+
+ @Test
+ public void copiedApprovalsWithStrangeTags() throws Exception {
+ String strangeTag = "!@#$%^\0&*):\" \n: \r\"#$@,. :";
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.CODE_REVIEW)))
+ .value(1)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .tag(strangeTag)
+ .build());
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ PatchSetApproval approval =
+ Iterables.getOnlyElement(notes.getApprovalsWithCopied().get(c.currentPatchSetId()));
+ assertThat(approval.accountId()).isEqualTo(changeOwner.getAccountId());
+ assertThat(approval.label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(approval.value()).isEqualTo((short) 1);
+ assertThat(approval.tag()).hasValue(NoteDbUtil.sanitizeFooter(strangeTag));
+ assertThat(approval.copied()).isTrue();
+ }
+
+ @Test
+ public void copiedApprovalsPostSubmit() throws Exception {
+ Change c = newChange();
+ SubmissionId submissionId = new SubmissionId(c);
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.CODE_REVIEW)))
+ .value(1)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .build());
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.VERIFIED)))
+ .value(1)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .build());
+ update.commit();
+
+ update = newUpdate(c, changeOwner);
+ update.merge(
+ submissionId,
+ ImmutableList.of(
+ submitRecord(
+ "NOT_READY",
+ null,
+ submitLabel(LabelId.VERIFIED, "OK", changeOwner.getAccountId()),
+ submitLabel(LabelId.CODE_REVIEW, "NEED", null))));
+ update.commit();
+
+ update = newUpdate(c, changeOwner);
+ update.putCopiedApproval(
+ PatchSetApproval.builder()
+ .key(
+ PatchSetApproval.key(
+ c.currentPatchSetId(),
+ changeOwner.getAccountId(),
+ LabelId.create(LabelId.CODE_REVIEW)))
+ .value(2)
+ .copied(true)
+ .granted(TimeUtil.nowTs())
+ .build());
+ update.commit();
+
+ ChangeNotes notes = newNotes(c);
+ List<PatchSetApproval> approvals = Lists.newArrayList(notes.getApprovalsWithCopied().values());
+ assertThat(approvals).hasSize(2);
+ assertThat(approvals.get(0).label()).isEqualTo(LabelId.VERIFIED);
+ assertThat(approvals.get(0).value()).isEqualTo((short) 1);
+ assertThat(approvals.get(0).postSubmit()).isFalse();
+ assertThat(approvals.get(1).label()).isEqualTo(LabelId.CODE_REVIEW);
+ assertThat(approvals.get(1).value()).isEqualTo((short) 2);
+ assertThat(approvals.get(1).postSubmit()).isTrue();
+ }
+
+ @Test
public void multipleReviewers() throws Exception {
Change c = newChange();
ChangeUpdate update = newUpdate(c, changeOwner);
diff --git a/javatests/com/google/gerrit/server/notedb/CommitRewriterTest.java b/javatests/com/google/gerrit/server/notedb/CommitRewriterTest.java
index 77db31f..26e1881 100644
--- a/javatests/com/google/gerrit/server/notedb/CommitRewriterTest.java
+++ b/javatests/com/google/gerrit/server/notedb/CommitRewriterTest.java
@@ -34,11 +34,11 @@
import com.google.gerrit.entities.RefNames;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.json.OutputFormat;
-import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.ReviewerStatusUpdate;
import com.google.gerrit.server.notedb.ChangeNoteUtil.AttentionStatusInNoteDb;
import com.google.gerrit.server.notedb.CommitRewriter.BackfillResult;
+import com.google.gerrit.server.notedb.CommitRewriter.CommitDiff;
import com.google.gerrit.server.notedb.CommitRewriter.RunOptions;
import com.google.gerrit.server.util.AccountTemplateUtil;
import com.google.gerrit.server.util.time.TimeUtil;
@@ -124,6 +124,38 @@
}
@Test
+ public void outputDiffOff_refsReported() throws Exception {
+ Change c = newChange();
+ ChangeUpdate update = newUpdate(c, changeOwner);
+ update.setChangeMessage("Change has been successfully merged by " + changeOwner.getName());
+ ObjectId commitToFix = update.commit();
+
+ ChangeUpdate updateWithSubject = newUpdate(c, changeOwner);
+ updateWithSubject.setSubjectForCommit("Update with subject");
+ updateWithSubject.commit();
+
+ Ref metaRefBefore = repo.exactRef(RefNames.changeMetaRef(c.getId()));
+ RunOptions options = new RunOptions();
+ options.dryRun = false;
+ options.outputDiff = false;
+ options.verifyCommits = false;
+ BackfillResult backfillResult = rewriter.backfillProject(project, repo, options);
+ assertThat(backfillResult.fixedRefDiff.keySet())
+ .containsExactly(RefNames.changeMetaRef(c.getId()));
+ Ref metaRefAfter = repo.exactRef(RefNames.changeMetaRef(c.getId()));
+
+ assertThat(metaRefBefore.getObjectId()).isNotEqualTo(metaRefAfter.getObjectId());
+
+ assertFixedCommits(ImmutableList.of(commitToFix), backfillResult, c.getId());
+
+ List<String> commitHistoryDiff = commitHistoryDiff(backfillResult, c.getId());
+ assertThat(commitHistoryDiff).containsExactly("");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
+ }
+
+ @Test
public void fixAuthorIdent() throws Exception {
Change c = newChange();
Timestamp when = TimeUtil.nowTs();
@@ -164,6 +196,8 @@
assertValidCommits(
commitsBeforeRewrite, commitsAfterRewrite, ImmutableList.of(invalidCommitIndex));
+ assertFixedCommits(ImmutableList.of(invalidUpdateCommit.getId()), result, c.getId());
+
RevCommit fixedUpdateCommit = commitsAfterRewrite.get(invalidCommitIndex);
PersonIdent originalAuthorIdent = invalidUpdateCommit.getAuthorIdent();
PersonIdent fixedAuthorIdent = fixedUpdateCommit.getAuthorIdent();
@@ -177,10 +211,13 @@
assertThat(invalidUpdateCommit.getCommitterIdent())
.isEqualTo(fixedUpdateCommit.getCommitterIdent());
assertThat(fixedUpdateCommit.getFullMessage()).doesNotContain(changeOwner.getName());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff).hasSize(1);
assertThat(commitHistoryDiff.get(0)).contains("-author Change Owner <1@gerrit>");
assertThat(commitHistoryDiff.get(0)).contains("+author Gerrit User 1 <1@gerrit>");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -188,7 +225,7 @@
Change c = newChange();
String realUserIdentToFix = getAccountIdentToFix(otherUser.getAccount());
- RevCommit invalidUpdateCommit =
+ ObjectId invalidUpdateCommit =
writeUpdate(
RefNames.changeMetaRef(c.getId()),
getChangeUpdateBody(c, "Comment on behalf of user", "Real-user: " + realUserIdentToFix),
@@ -233,31 +270,42 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(
commitsBeforeRewrite, commitsAfterRewrite, ImmutableList.of(invalidCommitIndex));
+ assertFixedCommits(ImmutableList.of(invalidUpdateCommit), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -9 +9 @@\n"
+ "-Real-user: Other Account <2@gerrit>\n"
+ "+Real-user: Gerrit User 2 <2@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
public void fixReviewerFooterIdent() throws Exception {
Change c = newChange();
String reviewerIdentToFix = getAccountIdentToFix(otherUser.getAccount());
- ImmutableList<RevCommit> commitsToFix =
- new ImmutableList.Builder<RevCommit>()
+ ImmutableList<ObjectId> commitsToFix =
+ new ImmutableList.Builder<ObjectId>()
.add(
writeUpdate(
RefNames.changeMetaRef(c.getId()),
+ // valid change message that should not be overwritten
getChangeUpdateBody(
- c, /*changeMessage=*/ null, "Reviewer: " + reviewerIdentToFix),
+ c,
+ "Removed reviewer <GERRIT_ACCOUNT_1>.",
+ "Reviewer: " + reviewerIdentToFix),
getAuthorIdent(changeOwner.getAccount())))
.add(
writeUpdate(
RefNames.changeMetaRef(c.getId()),
- getChangeUpdateBody(c, /*changeMessage=*/ null, "CC: " + reviewerIdentToFix),
+ // valid change message that should not be overwritten
+ getChangeUpdateBody(
+ c,
+ "Removed cc <GERRIT_ACCOUNT_2> with the following votes:\n\n * Code-Review+2 by <GERRIT_ACCOUNT_2>",
+ "CC: " + reviewerIdentToFix),
getAuthorIdent(otherUser.getAccount())))
.add(
writeUpdate(
@@ -299,23 +347,29 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix, result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
- "@@ -7 +7 @@\n"
+ "@@ -9 +9 @@\n"
+ "-Reviewer: Other Account <2@gerrit>\n"
+ "+Reviewer: Gerrit User 2 <2@gerrit>\n",
- "@@ -7 +7 @@\n" + "-CC: Other Account <2@gerrit>\n" + "+CC: Gerrit User 2 <2@gerrit>\n",
+ "@@ -11 +11 @@\n"
+ + "-CC: Other Account <2@gerrit>\n"
+ + "+CC: Gerrit User 2 <2@gerrit>\n",
"@@ -9 +9 @@\n"
+ "-Removed: Other Account <2@gerrit>\n"
+ "+Removed: Gerrit User 2 <2@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
public void fixReviewerMessage() throws Exception {
Change c = newChange();
- ImmutableList.Builder<RevCommit> commitsToFix = new ImmutableList.Builder<>();
+ ImmutableList.Builder<ObjectId> commitsToFix = new ImmutableList.Builder<>();
ChangeUpdate addReviewerUpdate = newUpdate(c, changeOwner);
addReviewerUpdate.putReviewer(otherUserId, REVIEWER);
addReviewerUpdate.commit();
@@ -325,7 +379,7 @@
RefNames.changeMetaRef(c.getId()),
getChangeUpdateBody(
c,
- "Removed reviewer " + otherUser.getAccount().fullName(),
+ String.format("Removed reviewer %s.", otherUser.getAccount().fullName()),
"Removed: " + getValidIdentAsString(otherUser.getAccount())),
getAuthorIdent(changeOwner.getAccount())));
@@ -338,7 +392,9 @@
RefNames.changeMetaRef(c.getId()),
getChangeUpdateBody(
c,
- "Removed cc " + otherUser.getAccount().fullName(),
+ String.format(
+ "Removed cc %s with the following votes:\n\n * Code-Review+2",
+ otherUser.getAccount().fullName()),
"Removed: " + getValidIdentAsString(otherUser.getAccount())),
getAuthorIdent(changeOwner.getAccount())));
@@ -378,7 +434,9 @@
assertThat(notesBeforeRewrite.getReviewerUpdates()).isEqualTo(expectedReviewerUpdates);
assertThat(changeMessages(notesBeforeRewrite))
- .containsExactly("Removed reviewer Other Account", "Removed cc Other Account");
+ .containsExactly(
+ "Removed reviewer Other Account.",
+ "Removed cc Other Account with the following votes:\n\n * Code-Review+2");
assertThat(notesAfterRewrite.getReviewerUpdates()).isEqualTo(expectedReviewerUpdates);
assertThat(changeMessages(notesAfterRewrite)).containsExactly("Removed reviewer", "Removed cc");
@@ -387,12 +445,58 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
- "@@ -6 +6 @@\n" + "-Removed reviewer Other Account\n" + "+Removed reviewer\n",
- "@@ -6 +6 @@\n" + "-Removed cc Other Account\n" + "+Removed cc\n");
+ "@@ -6 +6 @@\n" + "-Removed reviewer Other Account.\n" + "+Removed reviewer\n",
+ "@@ -6,3 +6 @@\n"
+ + "-Removed cc Other Account with the following votes:\n"
+ + "-\n"
+ + "- * Code-Review+2\n"
+ + "+Removed cc\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
+ }
+
+ @Test
+ public void fixReviewerMessageNoReviewerFooter() throws Exception {
+ Change c = newChange();
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c, String.format("Removed reviewer %s.", otherUser.getAccount().fullName())),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c,
+ String.format(
+ "Removed cc %s with the following votes:\n\n * Code-Review+2",
+ otherUser.getAccount().fullName())),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ RunOptions options = new RunOptions();
+ options.dryRun = false;
+ BackfillResult result = rewriter.backfillProject(project, repo, options);
+ assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
+
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ assertThat(commitHistoryDiff)
+ .containsExactly(
+ "@@ -6 +6 @@\n" + "-Removed reviewer Other Account.\n" + "+Removed reviewer\n",
+ "@@ -6,3 +6 @@\n"
+ + "-Removed cc Other Account with the following votes:\n"
+ + "-\n"
+ + "- * Code-Review+2\n"
+ + "+Removed cc\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -404,8 +508,8 @@
approvalUpdateByOtherUser.putApproval(VERIFIED, (short) -1);
approvalUpdateByOtherUser.commit();
- ImmutableList<RevCommit> commitsToFix =
- new ImmutableList.Builder<RevCommit>()
+ ImmutableList<ObjectId> commitsToFix =
+ new ImmutableList.Builder<ObjectId>()
.add(
writeUpdate(
RefNames.changeMetaRef(c.getId()),
@@ -506,8 +610,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix, result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -7,2 +7,2 @@\n"
@@ -523,6 +628,9 @@
"@@ -7 +7 @@\n"
+ "-Label: -Verified Change Owner <1@gerrit>\n"
+ "+Label: -Verified Gerrit User 1 <1@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -535,8 +643,8 @@
approvalUpdateByOtherUser.putApprovalFor(changeOwner.getAccountId(), VERIFIED, (short) -1);
approvalUpdateByOtherUser.commit();
- ImmutableList<RevCommit> commitsToFix =
- new ImmutableList.Builder<RevCommit>()
+ ImmutableList<ObjectId> commitsToFix =
+ new ImmutableList.Builder<ObjectId>()
.add(
writeUpdate(
RefNames.changeMetaRef(c.getId()),
@@ -626,8 +734,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix, result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
@@ -642,6 +751,9 @@
"@@ -6 +6 @@\n"
+ "-Removed Verified+2 by Change Owner <change@owner.com>\n"
+ "+Removed Verified+2 by <GERRIT_ACCOUNT_1>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -657,7 +769,7 @@
RefNames.changeMetaRef(c.getId()),
getChangeUpdateBody(
c,
- /*changeMessage=*/ "Removed Verified+2 by " + changeOwner.getNameEmail(),
+ /*changeMessage=*/ "Removed Verified+2 by " + otherUser.getNameEmail(),
"Label: -Verified"),
invalidAuthorIdent);
@@ -666,12 +778,123 @@
BackfillResult result = rewriter.backfillProject(project, repo, options);
assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ // Other Account does not applier in any change updates, replaced with default
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
- + "-Removed Verified+2 by Change Owner <change@owner.com>\n"
+ + "-Removed Verified+2 by Other Account <other@account.com>\n"
+ "+Removed Verified+2 by Gerrit Account\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
+ }
+
+ @Test
+ public void fixRemoveVoteChangeMessageWithNoFooterLabel() throws Exception {
+ Change c = newChange();
+ ChangeUpdate approvalUpdate = newUpdate(c, changeOwner);
+ approvalUpdate.putApproval(VERIFIED, (short) +2);
+
+ approvalUpdate.putApprovalFor(otherUserId, VERIFIED, (short) -1);
+ approvalUpdate.commit();
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+
+ // Even though footer is missing, accounts are matched among the account in change updates.
+ getChangeUpdateBody(c, /*changeMessage=*/ "Removed Verified-1 by Other Account (0002)"),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c, /*changeMessage=*/ "Removed Verified+2 by " + changeOwner.getNameEmail()),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ // No rewrite for default
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(c, /*changeMessage=*/ "Removed Verified+2 by Gerrit Account"),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ RunOptions options = new RunOptions();
+ options.dryRun = false;
+ BackfillResult result = rewriter.backfillProject(project, repo, options);
+ assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
+
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ assertThat(commitHistoryDiff)
+ .containsExactly(
+ "@@ -6 +6 @@\n"
+ + "-Removed Verified-1 by Other Account (0002)\n"
+ + "+Removed Verified-1 by <GERRIT_ACCOUNT_2>\n",
+ "@@ -6 +6 @@\n"
+ + "-Removed Verified+2 by Change Owner <change@owner.com>\n"
+ + "+Removed Verified+2 by <GERRIT_ACCOUNT_1>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
+ }
+
+ @Test
+ public void fixRemoveVotesChangeMessage() throws Exception {
+ Change c = newChange();
+ ChangeUpdate approvalUpdate = newUpdate(c, changeOwner);
+ approvalUpdate.putApproval(VERIFIED, (short) +2);
+
+ approvalUpdate.putApprovalFor(otherUserId, VERIFIED, (short) -1);
+ approvalUpdate.commit();
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+
+ // Even though footer is missing, accounts are matched among the account in change updates.
+ getChangeUpdateBody(
+ c,
+ /*changeMessage=*/ "Removed the following votes:\n"
+ + String.format("* Verified-1 by %s\n", otherUser.getNameEmail())),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c,
+ /*changeMessage=*/ "Removed the following votes:\n"
+ + String.format("* Verified+2 by %s\n", changeOwner.getNameEmail())
+ + String.format("* Verified-1 by %s\n", changeOwner.getNameEmail())
+ + String.format("* Code-Review by %s\n", otherUser.getNameEmail())),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ // No rewrite for default
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c,
+ /*changeMessage=*/ "Removed the following votes:\n"
+ + "* Verified+2 by Gerrit Account\n"
+ + "* Verified-1 by <GERRIT_ACCOUNT_2>\n"),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ RunOptions options = new RunOptions();
+ options.dryRun = false;
+ BackfillResult result = rewriter.backfillProject(project, repo, options);
+ assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
+
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ assertThat(commitHistoryDiff)
+ .containsExactly(
+ "@@ -7 +7 @@\n"
+ + "-* Verified-1 by Other Account <other@account.com>\n"
+ + "+* Verified-1 by <GERRIT_ACCOUNT_2>\n",
+ "@@ -7,3 +7,3 @@\n"
+ + "-* Verified+2 by Change Owner <change@owner.com>\n"
+ + "-* Verified-1 by Change Owner <change@owner.com>\n"
+ + "-* Code-Review by Other Account <other@account.com>\n"
+ + "+* Verified+2 by <GERRIT_ACCOUNT_1>\n"
+ + "+* Verified-1 by <GERRIT_ACCOUNT_1>\n"
+ + "+* Code-Review by <GERRIT_ACCOUNT_2>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -726,8 +949,19 @@
ChangeUpdate validAttentionSetUpdate = newUpdate(c, changeOwner);
validAttentionSetUpdate.addToPlannedAttentionSetUpdates(
AttentionSetUpdate.createForWrite(otherUserId, Operation.REMOVE, "Removed by someone"));
+ validAttentionSetUpdate.addToPlannedAttentionSetUpdates(
+ AttentionSetUpdate.createForWrite(
+ changeOwner.getAccountId(), Operation.ADD, "Added by someone"));
validAttentionSetUpdate.commit();
+ ChangeUpdate invalidRemovedByClickUpdate = newUpdate(c, changeOwner);
+ invalidRemovedByClickUpdate.addToPlannedAttentionSetUpdates(
+ AttentionSetUpdate.createForWrite(
+ changeOwner.getAccountId(),
+ Operation.REMOVE,
+ String.format("Removed by %s by clicking the attention icon", otherUser.getName())));
+ commitsToFix.add(invalidRemovedByClickUpdate.commit());
+
Ref metaRefBeforeRewrite = repo.exactRef(RefNames.changeMetaRef(c.getId()));
ImmutableList<RevCommit> commitsBeforeRewrite = logMetaRef(repo, metaRefBeforeRewrite);
@@ -747,6 +981,16 @@
ImmutableList<AttentionSetUpdate> attentionSetUpdatesBeforeRewrite =
ImmutableList.of(
AttentionSetUpdate.createFromRead(
+ invalidRemovedByClickUpdate.getWhen().toInstant(),
+ changeOwner.getAccountId(),
+ Operation.REMOVE,
+ String.format("Removed by %s by clicking the attention icon", otherUser.getName())),
+ AttentionSetUpdate.createFromRead(
+ validAttentionSetUpdate.getWhen().toInstant(),
+ changeOwner.getAccountId(),
+ Operation.ADD,
+ "Added by someone"),
+ AttentionSetUpdate.createFromRead(
validAttentionSetUpdate.getWhen().toInstant(),
otherUserId,
Operation.REMOVE,
@@ -780,6 +1024,16 @@
ImmutableList<AttentionSetUpdate> attentionSetUpdatesAfterRewrite =
ImmutableList.of(
AttentionSetUpdate.createFromRead(
+ invalidRemovedByClickUpdate.getWhen().toInstant(),
+ changeOwner.getAccountId(),
+ Operation.REMOVE,
+ "Removed by someone by clicking the attention icon"),
+ AttentionSetUpdate.createFromRead(
+ validAttentionSetUpdate.getWhen().toInstant(),
+ changeOwner.getAccountId(),
+ Operation.ADD,
+ "Added by someone"),
+ AttentionSetUpdate.createFromRead(
validAttentionSetUpdate.getWhen().toInstant(),
otherUserId,
Operation.REMOVE,
@@ -822,9 +1076,10 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
- assertThat(commitHistoryDiff).hasSize(3);
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ assertThat(commitHistoryDiff).hasSize(4);
assertThat(commitHistoryDiff.get(0))
.isEqualTo(
"@@ -8 +8 @@\n"
@@ -844,6 +1099,14 @@
"-Attention: {\"person_ident\":\"Change Owner \\u003c1@gerrit\\u003e\",\"operation\":\"REMOVE\",\"reason\":\"Other Account replied on the change\"}",
"+Attention: {\"person_ident\":\"Gerrit User 2 \\u003c2@gerrit\\u003e\",\"operation\":\"ADD\",\"reason\":\"Added by someone using the hovercard menu\"}",
"+Attention: {\"person_ident\":\"Gerrit User 1 \\u003c1@gerrit\\u003e\",\"operation\":\"REMOVE\",\"reason\":\"Someone replied on the change\"}");
+ assertThat(commitHistoryDiff.get(3))
+ .isEqualTo(
+ "@@ -7 +7 @@\n"
+ + "-Attention: {\"person_ident\":\"Gerrit User 1 \\u003c1@gerrit\\u003e\",\"operation\":\"REMOVE\",\"reason\":\"Removed by Other Account by clicking the attention icon\"}\n"
+ + "+Attention: {\"person_ident\":\"Gerrit User 1 \\u003c1@gerrit\\u003e\",\"operation\":\"REMOVE\",\"reason\":\"Removed by someone by clicking the attention icon\"}\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -882,16 +1145,19 @@
Operation.REMOVE,
String.format("Removed by %s using the hovercard menu", okAccountName)));
secondAttentionSetUpdate.commit();
- ChangeUpdate clearAttentionSetUpdate = newUpdate(c, changeOwner);
- clearAttentionSetUpdate.addToPlannedAttentionSetUpdates(
- AttentionSetUpdate.createForWrite(changeOwner.getAccountId(), Operation.REMOVE, "Clear"));
- clearAttentionSetUpdate.commit();
- attentionSetUpdatesBeforeRewrite.add(
- AttentionSetUpdate.createFromRead(
- clearAttentionSetUpdate.getWhen().toInstant(),
+ ChangeUpdate thirdAttentionSetUpdate = newUpdate(c, changeOwner);
+ thirdAttentionSetUpdate.addToPlannedAttentionSetUpdates(
+ AttentionSetUpdate.createForWrite(
changeOwner.getAccountId(),
Operation.REMOVE,
- "Clear"),
+ String.format("Removed by %s by clicking the attention icon", okAccountName)));
+ thirdAttentionSetUpdate.commit();
+ attentionSetUpdatesBeforeRewrite.add(
+ AttentionSetUpdate.createFromRead(
+ thirdAttentionSetUpdate.getWhen().toInstant(),
+ changeOwner.getAccountId(),
+ Operation.REMOVE,
+ String.format("Removed by %s by clicking the attention icon", okAccountName)),
AttentionSetUpdate.createFromRead(
secondAttentionSetUpdate.getWhen().toInstant(),
otherUserId,
@@ -907,7 +1173,6 @@
otherUserId,
Operation.ADD,
String.format("Added by %s using the hovercard menu", okAccountName)));
- clearAttentionSetUpdate.getNotes();
}
ChangeNotes notesBeforeRewrite = newNotes(c);
@@ -924,6 +1189,9 @@
assertThat(notesBeforeRewrite.getMetaId()).isEqualTo(notesAfterRewrite.getMetaId());
assertThat(metaRefBefore.getObjectId()).isEqualTo(metaRefAfter.getObjectId());
assertThat(backfillResult.fixedRefDiff).isEmpty();
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -934,19 +1202,19 @@
invalidMergedMessageUpdate.setChangeMessage(
"Change has been successfully merged by " + changeOwner.getName());
invalidMergedMessageUpdate.setTopic("");
- invalidMergedMessageUpdate.setTag(ChangeMessagesUtil.TAG_MERGED);
+
commitsToFix.add(invalidMergedMessageUpdate.commit());
ChangeUpdate invalidCherryPickedMessageUpdate = newUpdate(c, changeOwner);
invalidCherryPickedMessageUpdate.setChangeMessage(
"Change has been successfully cherry-picked as e40dc1a50dc7f457a37579e2755374f3e1a5413b by "
+ changeOwner.getName());
- invalidCherryPickedMessageUpdate.setTag(ChangeMessagesUtil.TAG_MERGED);
+
commitsToFix.add(invalidCherryPickedMessageUpdate.commit());
ChangeUpdate invalidRebasedMessageUpdate = newUpdate(c, changeOwner);
invalidRebasedMessageUpdate.setChangeMessage(
"Change has been successfully rebased and submitted as e40dc1a50dc7f457a37579e2755374f3e1a5413b by "
+ changeOwner.getName());
- invalidRebasedMessageUpdate.setTag(ChangeMessagesUtil.TAG_MERGED);
+
commitsToFix.add(invalidRebasedMessageUpdate.commit());
ChangeUpdate validSubmitMessageUpdate = newUpdate(c, changeOwner);
validSubmitMessageUpdate.setChangeMessage(
@@ -988,8 +1256,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
@@ -1001,6 +1270,9 @@
"@@ -6 +6 @@\n"
+ "-Change has been successfully rebased and submitted as e40dc1a50dc7f457a37579e2755374f3e1a5413b by Change Owner\n"
+ "+Change has been successfully rebased and submitted as e40dc1a50dc7f457a37579e2755374f3e1a5413b\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1032,7 +1304,7 @@
BackfillResult result = rewriter.backfillProject(project, repo, options);
assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -1 +1 @@\n"
@@ -1047,6 +1319,9 @@
+ "@@ -15 +15 @@\n"
+ "-Submitted-with: OK: Code-Review: Change Owner <1@gerrit>\n"
+ "+Submitted-with: OK: Code-Review: Gerrit User 1 <1@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1108,8 +1383,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(
commitsBeforeRewrite, commitsAfterRewrite, ImmutableList.of(invalidCommitIndex));
+ assertFixedCommits(ImmutableList.of(invalidUpdateCommit.getId()), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -10 +10 @@\n"
@@ -1118,6 +1394,9 @@
+ "@@ -12 +12 @@\n"
+ "-Submitted-with: OK: Verified: Change Owner <1@gerrit>\n"
+ "+Submitted-with: OK: Verified: Gerrit User 1 <1@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1179,8 +1458,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
@@ -1189,6 +1469,9 @@
"@@ -6 +6 @@\n"
+ "-Change message removed by: Change Owner\n"
+ "+Change message removed\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1288,8 +1571,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
@@ -1307,6 +1591,9 @@
"@@ -6 +6 @@\n"
+ "-Reviewer User who was added as reviewer owns the following files:\n"
+ "+Gerrit Account, who was added as reviewer owns the following files:\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1315,30 +1602,51 @@
Change c = newChange();
ImmutableList.Builder<ObjectId> commitsToFix = new ImmutableList.Builder<>();
- ChangeUpdate invalidOnApprovalUpdate = newUpdate(c, changeOwner);
- invalidOnApprovalUpdate.setChangeMessage(
- "Patch Set 1: Code-Review+2\n\n"
+ ChangeUpdate invalidOnReviewUpdate = newUpdate(c, changeOwner);
+ invalidOnReviewUpdate.setChangeMessage(
+ "Patch Set 1: Any-Label+2 Other-Label+2 Code-Review+2\n\n"
+ + "By voting Code-Review+2 the following files are now code-owner approved by Change Owner:\n"
+ + " * file1.java\n"
+ + " * file2.ts\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n"
+ + "By voting Other-Label+2 the code-owners submit requirement is still overridden by Change Owner\n");
+ commitsToFix.add(invalidOnReviewUpdate.commit());
+
+ ChangeUpdate invalidOnReviewUpdateAnyOrder = newUpdate(c, changeOwner);
+ invalidOnReviewUpdateAnyOrder.setChangeMessage(
+ "Patch Set 1: Any-Label+2 Other-Label+2 Code-Review+2\n\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n"
+ + "By voting Other-Label+2 the code-owners submit requirement is still overridden by Change Owner\n"
+ "By voting Code-Review+2 the following files are now code-owner approved by Change Owner:\n"
+ " * file1.java\n"
+ " * file2.ts\n");
- commitsToFix.add(invalidOnApprovalUpdate.commit());
- ChangeUpdate invalidOnApprovalMultipleByUpdate = newUpdate(c, otherUser);
- invalidOnApprovalMultipleByUpdate.setChangeMessage(
+ commitsToFix.add(invalidOnReviewUpdateAnyOrder.commit());
+ ChangeUpdate invalidOnApprovalUpdate = newUpdate(c, otherUser);
+ invalidOnApprovalUpdate.setChangeMessage(
"Patch Set 1: -Code-Review\n\n"
+ "By removing the Code-Review+2 vote the following files are no longer explicitly code-owner approved by Other Account:\n"
+ " * file1.java\n"
+ " * file2.ts\n"
+ "\nThe listed files are still implicitly approved by Other Account.\n");
- commitsToFix.add(invalidOnApprovalMultipleByUpdate.commit());
+ commitsToFix.add(invalidOnApprovalUpdate.commit());
ChangeUpdate invalidOnOverrideUpdate = newUpdate(c, changeOwner);
invalidOnOverrideUpdate.setChangeMessage(
"Patch Set 1: -Owners-Override\n\n"
+ "(1 comment)\n\n"
- + "By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by Change Owner:\n"
- + " * file3.java\n");
+ + "By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by Change Owner\n");
+
commitsToFix.add(invalidOnOverrideUpdate.commit());
+ ChangeUpdate partiallyValidOnReviewUpdate = newUpdate(c, changeOwner);
+ partiallyValidOnReviewUpdate.setChangeMessage(
+ "Patch Set 1: Any-Label+2 Code-Review+2\n\n"
+ + "By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ + " * file1.java\n"
+ + " * file2.ts\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n");
+ commitsToFix.add(partiallyValidOnReviewUpdate.commit());
+
ChangeUpdate validOnApprovalUpdate = newUpdate(c, changeOwner);
validOnApprovalUpdate.setChangeMessage(
"Patch Set 1: Code-Review-2\n\n"
@@ -1349,8 +1657,7 @@
ChangeUpdate validOnOverrideUpdate = newUpdate(c, changeOwner);
validOnOverrideUpdate.setChangeMessage(
"Patch Set 1: Owners-Override+1\n\n"
- + "By voting Owners-Override+1 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>:\n"
- + " * file1.java\n");
+ + "By voting Owners-Override+1 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n");
validOnOverrideUpdate.commit();
Ref metaRefBeforeRewrite = repo.exactRef(RefNames.changeMetaRef(c.getId()));
@@ -1370,11 +1677,18 @@
ChangeNotes notesAfterRewrite = newNotes(c);
- assertThat(changeMessages(notesBeforeRewrite)).hasSize(5);
+ assertThat(changeMessages(notesBeforeRewrite)).hasSize(7);
assertThat(changeMessages(notesAfterRewrite))
.containsExactly(
- "Patch Set 1: Code-Review+2\n"
- + "\n"
+ "Patch Set 1: Any-Label+2 Other-Label+2 Code-Review+2\n\n"
+ + "By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ + " * file1.java\n"
+ + " * file2.ts\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n"
+ + "By voting Other-Label+2 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n",
+ "Patch Set 1: Any-Label+2 Other-Label+2 Code-Review+2\n\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n"
+ + "By voting Other-Label+2 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n"
+ "By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ " * file1.java\n"
+ " * file2.ts\n",
@@ -1388,27 +1702,43 @@
+ "\n"
+ "(1 comment)\n"
+ "\n"
- + "By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by <GERRIT_ACCOUNT_1>:\n"
- + " * file3.java\n",
+ + "By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by <GERRIT_ACCOUNT_1>\n",
+ "Patch Set 1: Any-Label+2 Code-Review+2\n\n"
+ + "By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ + " * file1.java\n"
+ + " * file2.ts\n"
+ + "By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n",
"Patch Set 1: Code-Review-2\n\n"
+ "By voting Code-Review-2 the following files are no longer explicitly code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ " * file4.java\n",
"Patch Set 1: Owners-Override+1\n"
+ "\n"
- + "By voting Owners-Override+1 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>:\n"
- + " * file1.java\n");
+ + "By voting Owners-Override+1 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n");
Ref metaRefAfterRewrite = repo.exactRef(RefNames.changeMetaRef(c.getId()));
assertThat(metaRefAfterRewrite.getObjectId()).isNotEqualTo(metaRefBeforeRewrite.getObjectId());
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
+ assertFixedCommits(commitsToFix.build(), result, c.getId());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -8 +8 @@\n"
+ "-By voting Code-Review+2 the following files are now code-owner approved by Change Owner:\n"
+ + "+By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n"
+ + "@@ -11,2 +11,2 @@\n"
+ + "-By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n"
+ + "-By voting Other-Label+2 the code-owners submit requirement is still overridden by Change Owner\n"
+ + "+By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n"
+ + "+By voting Other-Label+2 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n",
+ "@@ -8,3 +8,3 @@\n"
+ + "-By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n"
+ + "-By voting Other-Label+2 the code-owners submit requirement is still overridden by Change Owner\n"
+ + "-By voting Code-Review+2 the following files are now code-owner approved by Change Owner:\n"
+ + "+By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n"
+ + "+By voting Other-Label+2 the code-owners submit requirement is still overridden by <GERRIT_ACCOUNT_1>\n"
+ "+By voting Code-Review+2 the following files are now code-owner approved by <GERRIT_ACCOUNT_1>:\n",
"@@ -8 +8 @@\n"
+ "-By removing the Code-Review+2 vote the following files are no longer explicitly code-owner approved by Other Account:\n"
@@ -1417,8 +1747,14 @@
+ "-The listed files are still implicitly approved by Other Account.\n"
+ "+The listed files are still implicitly approved by <GERRIT_ACCOUNT_2>.\n",
"@@ -10 +10 @@\n"
- + "-By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by Change Owner:\n"
- + "+By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by <GERRIT_ACCOUNT_1>:\n");
+ + "-By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by Change Owner\n"
+ + "+By removing the Owners-Override+1 vote the code-owners submit requirement is no longer overridden by <GERRIT_ACCOUNT_1>\n",
+ "@@ -11 +11 @@\n"
+ + "-By voting Any-Label+2 the code-owners submit requirement is overridden by Change Owner\n"
+ + "+By voting Any-Label+2 the code-owners submit requirement is overridden by <GERRIT_ACCOUNT_1>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1466,6 +1802,7 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(
commitsBeforeRewrite, commitsAfterRewrite, ImmutableList.of(invalidCommitIndex));
+ assertFixedCommits(ImmutableList.of(invalidUpdateCommit.getId()), result, c.getId());
RevCommit fixedUpdateCommit = commitsAfterRewrite.get(invalidCommitIndex);
assertThat(invalidUpdateCommit.getAuthorIdent()).isEqualTo(fixedUpdateCommit.getAuthorIdent());
@@ -1478,20 +1815,23 @@
String expectedFixedIdent = getValidIdentAsString(changeOwner.getAccount());
assertThat(fixedUpdateCommit.getFullMessage()).contains(expectedFixedIdent);
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -9 +9 @@\n"
+ "-Assignee: Change Owner <1@gerrit>\n"
+ "+Assignee: Gerrit User 1 <1@gerrit>\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
public void fixAssigneeChangeMessage() throws Exception {
Change c = newChange();
- ImmutableList<RevCommit> commitsToFix =
- new ImmutableList.Builder<RevCommit>()
+ ImmutableList<ObjectId> commitsToFix =
+ new ImmutableList.Builder<ObjectId>()
.add(
writeUpdate(
RefNames.changeMetaRef(c.getId()),
@@ -1561,7 +1901,9 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(commitsBeforeRewrite, commitsAfterRewrite, invalidCommits);
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ assertFixedCommits(commitsToFix, result, c.getId());
+
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff)
.containsExactly(
"@@ -6 +6 @@\n"
@@ -1577,6 +1919,70 @@
+ "@@ -9 +9 @@\n"
+ "-Assignee:\n"
+ "+Assignee: \n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
+ }
+
+ @Test
+ public void fixAssigneeChangeMessageNoAssigneeFooter() throws Exception {
+ Change c = newChange();
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(c, "Assignee added: " + changeOwner.getName()),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(
+ c,
+ String.format(
+ "Assignee changed from: %s to: %s", changeOwner.getName(), otherUser.getName())),
+ getAuthorIdent(otherUser.getAccount()));
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(c, "Assignee deleted: " + otherUser.getName()),
+ getAuthorIdent(changeOwner.getAccount()));
+ Account reviewer =
+ Account.builder(Account.id(3), TimeUtil.nowTs())
+ .setFullName("Reviewer User")
+ .setPreferredEmail("reviewer@account.com")
+ .build();
+ accountCache.put(reviewer);
+ // Even though account is present in the cache, it won't be used because it does not appear in
+ // the history of this change.
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(c, "Assignee added: " + reviewer.getName()),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ writeUpdate(
+ RefNames.changeMetaRef(c.getId()),
+ getChangeUpdateBody(c, "Assignee deleted: Gerrit Account"),
+ getAuthorIdent(changeOwner.getAccount()));
+
+ RunOptions options = new RunOptions();
+ options.dryRun = false;
+ BackfillResult result = rewriter.backfillProject(project, repo, options);
+ assertThat(result.fixedRefDiff.keySet()).containsExactly(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
+ assertThat(commitHistoryDiff)
+ .containsExactly(
+ "@@ -6 +6 @@\n"
+ + "-Assignee added: Change Owner\n"
+ + "+Assignee added: <GERRIT_ACCOUNT_1>\n",
+ "@@ -6 +6 @@\n"
+ + "-Assignee changed from: Change Owner to: Other Account\n"
+ + "+Assignee changed from: <GERRIT_ACCOUNT_1> to: <GERRIT_ACCOUNT_2>\n",
+ "@@ -6 +6 @@\n"
+ + "-Assignee deleted: Other Account\n"
+ + "+Assignee deleted: <GERRIT_ACCOUNT_2>\n",
+ "@@ -6 +6 @@\n"
+ + "-Assignee added: Reviewer User\n"
+ + "+Assignee added: Gerrit Account\n");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
@Test
@@ -1621,6 +2027,7 @@
ImmutableList<RevCommit> commitsAfterRewrite = logMetaRef(repo, metaRefAfterRewrite);
assertValidCommits(
commitsBeforeRewrite, commitsAfterRewrite, ImmutableList.of(invalidCommitIndex));
+ assertFixedCommits(ImmutableList.of(invalidUpdateCommit.getId()), result, c.getId());
RevCommit fixedUpdateCommit = commitsAfterRewrite.get(invalidCommitIndex);
assertThat(invalidUpdateCommit.getAuthorIdent())
@@ -1629,7 +2036,7 @@
assertThat(fixedUpdateCommit.getFullMessage()).doesNotContain(changeOwner.getName());
assertThat(fixedUpdateCommit.getFullMessage()).doesNotContain(otherUser.getName());
- List<String> commitHistoryDiff = result.fixedRefDiff.get(RefNames.changeMetaRef(c.getId()));
+ List<String> commitHistoryDiff = commitHistoryDiff(result, c.getId());
assertThat(commitHistoryDiff).hasSize(1);
assertThat(commitHistoryDiff.get(0)).contains("-author Change Owner <1@gerrit>");
assertThat(commitHistoryDiff.get(0)).contains("+author Gerrit User 1 <1@gerrit>");
@@ -1641,6 +2048,9 @@
+ "@@ -9 +9 @@\n"
+ "-Assignee: Other Account <2@gerrit>\n"
+ "+Assignee: Gerrit User 2 <2@gerrit>");
+ BackfillResult secondRunResult = rewriter.backfillProject(project, repo, options);
+ assertThat(secondRunResult.fixedRefDiff.keySet()).isEmpty();
+ assertThat(secondRunResult.refsFailedToFix).isEmpty();
}
private RevCommit writeUpdate(String metaRef, String body, PersonIdent author) throws Exception {
@@ -1702,6 +2112,15 @@
}
}
+ private void assertFixedCommits(
+ ImmutableList<ObjectId> expectedFixedCommits, BackfillResult result, Change.Id changeId) {
+ assertThat(expectedFixedCommits)
+ .containsExactlyElementsIn(
+ result.fixedRefDiff.get(RefNames.changeMetaRef(changeId)).stream()
+ .map(CommitDiff::oldSha1)
+ .collect(toImmutableList()));
+ }
+
private String getAccountIdentToFix(Account account) {
return String.format("%s <%s>", account.getName(), account.id().get() + "@" + serverId);
}
@@ -1718,6 +2137,12 @@
.collect(toImmutableList());
}
+ private ImmutableList<String> commitHistoryDiff(BackfillResult result, Change.Id changeId) {
+ return result.fixedRefDiff.get(RefNames.changeMetaRef(changeId)).stream()
+ .map(CommitDiff::diff)
+ .collect(toImmutableList());
+ }
+
private PersonIdent getAuthorIdent(Account account) {
Timestamp when = TimeUtil.nowTs();
return changeNoteUtil.newAccountIdIdent(account.id(), when, serverIdent);
diff --git a/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java b/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java
index 9ec1625..0ba3b56 100644
--- a/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java
+++ b/javatests/com/google/gerrit/server/permissions/SectionSortCacheTest.java
@@ -78,7 +78,7 @@
// Cache preserves relative order (reference equality) for identical elements
AccessSection[] expected = {sectionBClone, sectionB, sectionA, sectionAClone, sectionA};
for (int i = 0; i < sorted.size(); i++) {
- assert (sorted.get(i) == expected[i]);
+ assertThat(sorted.get(i)).isSameInstanceAs(expected[i]);
}
}
}
diff --git a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
index 1035fe7..5daf68e 100644
--- a/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
+++ b/javatests/com/google/gerrit/server/project/CommitsCollectionTest.java
@@ -64,6 +64,7 @@
@Inject protected AllProjectsName allProjects;
@Inject private CommitsCollection commits;
@Inject private ProjectOperations projectOperations;
+ @Inject private AuthRequest.Factory authRequestFactory;
private TestRepository<InMemoryRepository> repo;
private Project.NameKey project;
@@ -72,7 +73,8 @@
public void setUp() throws Exception {
setUpPermissions();
- Account.Id user = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ Account.Id user =
+ accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
testEnvironment.setApiUser(user);
project = projectOperations.newProject().create();
repo = new TestRepository<>(repoManager.openRepository(project));
diff --git a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
index 9130d3e..7f0b685 100644
--- a/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
+++ b/javatests/com/google/gerrit/server/project/ProjectConfigTest.java
@@ -36,6 +36,7 @@
import com.google.gerrit.entities.SubmitRequirementExpression;
import com.google.gerrit.extensions.client.InheritableBoolean;
import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.FileBasedAllProjectsConfigProvider;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
@@ -68,7 +69,10 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+@RunWith(JUnit4.class)
public class ProjectConfigTest {
private static final String LABEL_SCORES_CONFIG =
" copyAnyScore = "
@@ -113,7 +117,8 @@
public void setUp() throws Exception {
sitePaths = new SitePaths(temporaryFolder.newFolder().toPath());
Files.createDirectories(sitePaths.etc_dir);
- factory = new ProjectConfig.Factory(sitePaths, ALL_PROJECTS);
+ factory =
+ new ProjectConfig.Factory(ALL_PROJECTS, new FileBasedAllProjectsConfigProvider(sitePaths));
db = new InMemoryRepository(new DfsRepositoryDescription("repo"));
tr = new TestRepository<>(db);
}
@@ -327,8 +332,8 @@
assertThat(cfg.getValidationErrors()).hasSize(1);
assertThat(Iterables.getOnlyElement(cfg.getValidationErrors()).getMessage())
.isEqualTo(
- "project.config: Submit requirement \"code-review\" does not define a submittability expression."
- + " Skipping this requirement.");
+ "project.config: Submit requirement \"code-review\" does not define a submittability"
+ + " expression. Skipping this requirement.");
}
@Test
@@ -866,7 +871,9 @@
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
- "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+ "[commentlink \"bugzilla\"]\n"
+ + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+ + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
}
@Test
@@ -891,7 +898,9 @@
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
- "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+ "[commentlink \"bugzilla\"]\n"
+ + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+ + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
}
@Test
@@ -913,7 +922,9 @@
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
- "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+ "[commentlink \"bugzilla\"]\n"
+ + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+ + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
}
@Test
@@ -978,7 +989,9 @@
rev = commit(cfg);
assertThat(text(rev, "project.config"))
.isEqualTo(
- "[commentlink \"bugzilla\"]\n\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
+ "[commentlink \"bugzilla\"]\n"
+ + "\tmatch = \"(bug\\\\s+#?)(\\\\d+)\"\n"
+ + "\tlink = http://bugs.example.com/show_bug.cgi?id=$2\n");
}
@Test
@@ -987,8 +1000,11 @@
Path tmp = Files.createTempFile("gerrit_test_", "_site");
Files.deleteIfExists(tmp);
SitePaths sitePaths = new SitePaths(tmp);
+ FileBasedAllProjectsConfigProvider allProjectsConfigProvider =
+ new FileBasedAllProjectsConfigProvider(sitePaths);
byte[] hashedContents =
- ProjectCacheImpl.allProjectsFileProjectConfigHash(ALL_PROJECTS, sitePaths);
+ ProjectCacheImpl.allProjectsFileProjectConfigHash(
+ allProjectsConfigProvider.get(ALL_PROJECTS));
assertThat(hashedContents).isEqualTo(new byte[16]); // Empty/absent config
FileBasedConfig fileBasedConfig =
new FileBasedConfig(
@@ -1000,7 +1016,9 @@
FS.DETECTED);
fileBasedConfig.setString("plugin", "my-plugin", "key", "value");
fileBasedConfig.save();
- hashedContents = ProjectCacheImpl.allProjectsFileProjectConfigHash(ALL_PROJECTS, sitePaths);
+ hashedContents =
+ ProjectCacheImpl.allProjectsFileProjectConfigHash(
+ allProjectsConfigProvider.get(ALL_PROJECTS));
assertThat(hashedContents)
.isEqualTo(
new byte[] {
diff --git a/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
new file mode 100644
index 0000000..05eb6e0
--- /dev/null
+++ b/javatests/com/google/gerrit/server/project/SubmitRequirementsAdapterTest.java
@@ -0,0 +1,317 @@
+// 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.project;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.entities.LabelFunction;
+import com.google.gerrit.entities.LabelType;
+import com.google.gerrit.entities.LabelValue;
+import com.google.gerrit.entities.SubmitRecord;
+import com.google.gerrit.entities.SubmitRecord.Label;
+import com.google.gerrit.entities.SubmitRecord.Status;
+import com.google.gerrit.entities.SubmitRequirementExpressionResult;
+import com.google.gerrit.entities.SubmitRequirementResult;
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SubmitRequirementsAdapterTest {
+ private List<LabelType> labelTypes;
+
+ private static final ObjectId psCommitId = ObjectId.zeroId();
+
+ @Before
+ public void setup() {
+ LabelType codeReview =
+ LabelType.builder(
+ "Code-Review",
+ ImmutableList.of(
+ LabelValue.create((short) 1, "Looks good to me"),
+ LabelValue.create((short) 0, "No score"),
+ LabelValue.create((short) -1, "I would prefer this is not merged as is")))
+ .setFunction(LabelFunction.MAX_WITH_BLOCK)
+ .build();
+
+ LabelType verified =
+ LabelType.builder(
+ "Verified",
+ ImmutableList.of(
+ LabelValue.create((short) 1, "Looks good to me"),
+ LabelValue.create((short) 0, "No score"),
+ LabelValue.create((short) -1, "I would prefer this is not merged as is")))
+ .setFunction(LabelFunction.MAX_NO_BLOCK)
+ .build();
+
+ LabelType codeStyle =
+ LabelType.builder(
+ "Code-Style",
+ ImmutableList.of(
+ LabelValue.create((short) 1, "Looks good to me"),
+ LabelValue.create((short) 0, "No score"),
+ LabelValue.create((short) -1, "I would prefer this is not merged as is")))
+ .setFunction(LabelFunction.ANY_WITH_BLOCK)
+ .build();
+
+ LabelType ignoreSelfApprovalLabel =
+ LabelType.builder(
+ "ISA-Label",
+ ImmutableList.of(
+ LabelValue.create((short) 1, "Looks good to me"),
+ LabelValue.create((short) 0, "No score"),
+ LabelValue.create((short) -1, "I would prefer this is not merged as is")))
+ .setFunction(LabelFunction.MAX_WITH_BLOCK)
+ .setIgnoreSelfApproval(true)
+ .build();
+
+ labelTypes = Arrays.asList(codeReview, verified, codeStyle, ignoreSelfApprovalLabel);
+ }
+
+ @Test
+ public void defaultSubmitRule_withLabelsAllPass() {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~DefaultSubmitRule",
+ Status.OK,
+ Arrays.asList(
+ createLabel("Code-Review", Label.Status.OK),
+ createLabel("Verified", Label.Status.OK)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(2);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "Code-Review",
+ /* submitExpression= */ "label:Code-Review=MAX -label:Code-Review=MIN",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ assertResult(
+ requirements.get(1),
+ /* reqName= */ "Verified",
+ /* submitExpression= */ "label:Verified=MAX",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ }
+
+ @Test
+ public void defaultSubmitRule_withLabelsAllNeed() {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~DefaultSubmitRule",
+ Status.OK,
+ Arrays.asList(
+ createLabel("Code-Review", Label.Status.NEED),
+ createLabel("Verified", Label.Status.NEED)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(2);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "Code-Review",
+ /* submitExpression= */ "label:Code-Review=MAX -label:Code-Review=MIN",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ assertResult(
+ requirements.get(1),
+ /* reqName= */ "Verified",
+ /* submitExpression= */ "label:Verified=MAX",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ }
+
+ @Test
+ public void defaultSubmitRule_withLabelStatusNeed_labelHasIgnoreSelfApproval() throws Exception {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~DefaultSubmitRule",
+ Status.NOT_READY,
+ Arrays.asList(createLabel("ISA-Label", Label.Status.NEED)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "ISA-Label",
+ /* submitExpression= */ "label:ISA-Label=MAX,user=non_uploader -label:ISA-Label=MIN",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ }
+
+ @Test
+ public void defaultSubmitRule_withLabelStatusOk_labelHasIgnoreSelfApproval() throws Exception {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~DefaultSubmitRule",
+ Status.OK,
+ Arrays.asList(createLabel("ISA-Label", Label.Status.OK)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "ISA-Label",
+ /* submitExpression= */ "label:ISA-Label=MAX,user=non_uploader -label:ISA-Label=MIN",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ }
+
+ @Test
+ public void customSubmitRule_noLabels_withStatusOk() {
+ SubmitRecord submitRecord =
+ createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.OK, Arrays.asList());
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "gerrit~IgnoreSelfApprovalRule",
+ /* submitExpression= */ "rule:gerrit~IgnoreSelfApprovalRule",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ }
+
+ @Test
+ public void customSubmitRule_nullLabels_withStatusOk() {
+ SubmitRecord submitRecord =
+ createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.OK, /* labels= */ null);
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "gerrit~IgnoreSelfApprovalRule",
+ /* submitExpression= */ "rule:gerrit~IgnoreSelfApprovalRule",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ }
+
+ @Test
+ public void customSubmitRule_noLabels_withStatusNotReady() {
+ SubmitRecord submitRecord =
+ createSubmitRecord("gerrit~IgnoreSelfApprovalRule", Status.NOT_READY, Arrays.asList());
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(1);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "gerrit~IgnoreSelfApprovalRule",
+ /* submitExpression= */ "rule:gerrit~IgnoreSelfApprovalRule",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ }
+
+ @Test
+ public void customSubmitRule_withLabels() {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~PrologRule",
+ Status.NOT_READY,
+ Arrays.asList(
+ createLabel("custom-label-1", Label.Status.NEED),
+ createLabel("custom-label-2", Label.Status.REJECT)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(2);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "custom-label-1",
+ /* submitExpression= */ "label:custom-label-1=gerrit~PrologRule",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ assertResult(
+ requirements.get(1),
+ /* reqName= */ "custom-label-2",
+ /* submitExpression= */ "label:custom-label-2=gerrit~PrologRule",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ }
+
+ @Test
+ public void customSubmitRule_withMixOfPassingAndFailingLabels() {
+ SubmitRecord submitRecord =
+ createSubmitRecord(
+ "gerrit~PrologRule",
+ Status.NOT_READY,
+ Arrays.asList(
+ createLabel("custom-label-1", Label.Status.OK),
+ createLabel("custom-label-2", Label.Status.REJECT)));
+
+ List<SubmitRequirementResult> requirements =
+ SubmitRequirementsAdapter.createResult(submitRecord, labelTypes, psCommitId);
+
+ assertThat(requirements).hasSize(2);
+ assertResult(
+ requirements.get(0),
+ /* reqName= */ "custom-label-1",
+ /* submitExpression= */ "label:custom-label-1=gerrit~PrologRule",
+ SubmitRequirementResult.Status.SATISFIED,
+ SubmitRequirementExpressionResult.Status.PASS);
+ assertResult(
+ requirements.get(1),
+ /* reqName= */ "custom-label-2",
+ /* submitExpression= */ "label:custom-label-2=gerrit~PrologRule",
+ SubmitRequirementResult.Status.UNSATISFIED,
+ SubmitRequirementExpressionResult.Status.FAIL);
+ }
+
+ private void assertResult(
+ SubmitRequirementResult r,
+ String reqName,
+ String submitExpression,
+ SubmitRequirementResult.Status status,
+ SubmitRequirementExpressionResult.Status expressionStatus) {
+ assertThat(r.submitRequirement().name()).isEqualTo(reqName);
+ assertThat(r.submitRequirement().submittabilityExpression().expressionString())
+ .isEqualTo(submitExpression);
+ assertThat(r.status()).isEqualTo(status);
+ assertThat(r.submittabilityExpressionResult().status()).isEqualTo(expressionStatus);
+ }
+
+ private SubmitRecord createSubmitRecord(
+ String ruleName, SubmitRecord.Status status, @Nullable List<Label> labels) {
+ SubmitRecord record = new SubmitRecord();
+ record.ruleName = ruleName;
+ record.status = status;
+ record.labels = labels;
+ return record;
+ }
+
+ private Label createLabel(String name, Label.Status status) {
+ Label label = new Label();
+ label.label = name;
+ label.status = status;
+ return label;
+ }
+}
diff --git a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
index b7be40b..16f7199 100644
--- a/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/AbstractQueryAccountsTest.java
@@ -65,6 +65,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdKeyFactory;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
@@ -139,6 +140,10 @@
@Inject protected ExternalIds externalIds;
+ @Inject private ExternalIdKeyFactory externalIdKeyFactory;
+
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
protected LifecycleManager lifecycle;
protected Injector injector;
protected AccountInfo currentUserInfo;
@@ -659,7 +664,7 @@
List<AccountExternalIdInfo> externalIdInfos = gApi.accounts().self().getExternalIds();
List<ByteArrayWrapper> blobs = new ArrayList<>();
for (AccountExternalIdInfo info : externalIdInfos) {
- Optional<ExternalId> extId = externalIds.get(ExternalId.Key.parse(info.identity));
+ Optional<ExternalId> extId = externalIds.get(externalIdKeyFactory.parse(info.identity));
assertThat(extId).isPresent();
blobs.add(new ByteArrayWrapper(extId.get().toByteArray()));
}
@@ -772,9 +777,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
@@ -791,7 +797,7 @@
private void addEmails(AccountInfo account, String... emails) throws Exception {
Account.Id id = Account.id(account._accountId);
for (String email : emails) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountIndexer.index(id);
}
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 1f29f45..9ebee9c 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -42,6 +42,9 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Streams;
import com.google.common.truth.ThrowableSubject;
+import com.google.gerrit.acceptance.ExtensionRegistry;
+import com.google.gerrit.acceptance.ExtensionRegistry.Registration;
+import com.google.gerrit.acceptance.FakeSubmitRule;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.acceptance.testsuite.project.ProjectOperations;
import com.google.gerrit.common.Nullable;
@@ -68,7 +71,6 @@
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.api.changes.ReviewInput.DraftHandling;
import com.google.gerrit.extensions.api.changes.ReviewerInput;
-import com.google.gerrit.extensions.api.changes.StarsInput;
import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.api.projects.ProjectInput;
@@ -103,7 +105,7 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.account.VersionedAccountQueries;
-import com.google.gerrit.server.account.externalids.ExternalId;
+import com.google.gerrit.server.account.externalids.ExternalIdFactory;
import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.change.NotifyResolver;
@@ -137,7 +139,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -174,6 +175,7 @@
@Inject protected IdentifiedUser.GenericFactory userFactory;
@Inject protected ChangeIndexCollection indexes;
@Inject protected ChangeIndexer indexer;
+ @Inject protected ExtensionRegistry extensionRegistry;
@Inject protected IndexConfig indexConfig;
@Inject protected InMemoryRepositoryManager repoManager;
@Inject protected Provider<AnonymousUser> anonymousUserProvider;
@@ -190,6 +192,8 @@
@Inject protected ProjectCache projectCache;
@Inject protected MetaDataUpdate.Server metaDataUpdateFactory;
@Inject protected IdentifiedUser.GenericFactory identifiedUserFactory;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+ @Inject protected ExternalIdFactory externalIdFactory;
@Inject private ProjectConfig.Factory projectConfigFactory;
@Inject private ProjectOperations projectOperations;
@@ -224,14 +228,16 @@
protected void setUpDatabase() throws Exception {
schemaCreator.create();
- userId = accountManager.authenticate(AuthRequest.forUser("user")).getAccountId();
+ userId = accountManager.authenticate(authRequestFactory.createForUser("user")).getAccountId();
String email = "user@example.com";
accountsUpdate
.get()
.update(
"Add Email",
userId,
- u -> u.addExternalId(ExternalId.createEmail(userId, email)).setPreferredEmail(email));
+ u ->
+ u.addExternalId(externalIdFactory.createEmail(userId, email))
+ .setPreferredEmail(email));
resetUser();
}
@@ -415,7 +421,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
// No private changes.
@@ -583,7 +589,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
assertQuery("is:owner", change1);
@@ -621,9 +627,14 @@
PersonIdent johnDoe = new PersonIdent("John Doe", "john.doe@example.com");
PersonIdent john = new PersonIdent("John", "john@example.com");
PersonIdent doeSmith = new PersonIdent("Doe Smith", "doe_smith@example.com");
+ Account ua = user.asIdentifiedUser().getAccount();
+ PersonIdent myself = new PersonIdent("I Am", ua.preferredEmail());
+ PersonIdent selfName = new PersonIdent("My Self", "my.self@example.com");
+
Change change1 = createChange(repo, johnDoe);
Change change2 = createChange(repo, john);
Change change3 = createChange(repo, doeSmith);
+ createChange(repo, selfName);
// Only email address.
assertQuery(searchOperator + "john.doe@example.com", change1);
@@ -639,6 +650,18 @@
assertQuery(searchOperator + "\"John <john.doe@example.com>\"");
assertQuery(searchOperator + "\"Doe John <john@example.com>\"");
assertQuery(searchOperator + "\"Doe John <doe_smith@example.com>\"");
+
+ // Partial name
+ assertQuery(searchOperator + "ohn");
+ assertQuery(searchOperator + "smith", change3);
+
+ // The string 'self' in the name should not be matched
+ assertQuery(searchOperator + "self");
+
+ // ':self' matches a change created with the current user's email address
+ Change change5 = createChange(repo, myself);
+ assertQuery(searchOperator + "me", change5);
+ assertQuery(searchOperator + "self", change5);
}
private void byAuthorOrCommitterFullText(String searchOperator) throws Exception {
@@ -680,7 +703,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
Change change3 = insert(repo, newChange(repo), user2);
gApi.changes().id(change3.getId().get()).current().review(ReviewInput.approve());
@@ -970,7 +993,7 @@
@Test
public void byLabel() throws Exception {
- accountManager.authenticate(AuthRequest.forUser("anotheruser"));
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser"));
TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo);
ChangeInserter ins2 = newChange(repo);
@@ -1143,6 +1166,26 @@
assertQuery("label:Code-Review=+1,owner");
}
+ @Test
+ public void byLabelNonUploader() throws Exception {
+ TestRepository<Repo> repo = createProject("repo");
+ ChangeInserter ins = newChange(repo);
+ Account.Id user1 = createAccount("user1");
+
+ // create a change with "user"
+ Change reviewPlus1Change = insert(repo, ins);
+
+ // add a +1 vote with "user". Query doesn't match since voter is the uploader.
+ gApi.changes().id(reviewPlus1Change.getId().get()).current().review(ReviewInput.recommend());
+ assertQuery("label:Code-Review=+1,user=non_uploader");
+
+ // add a +1 vote with "user1". Query will match since voter is a non-uploader.
+ requestContext.setContext(newRequestContext(user1));
+ gApi.changes().id(reviewPlus1Change.getId().get()).current().review(ReviewInput.recommend());
+ assertQuery("label:Code-Review=+1,user=non_uploader", reviewPlus1Change);
+ assertQuery("label:Code-Review=+1,non_uploader", reviewPlus1Change);
+ }
+
private Change[] codeReviewInRange(Map<Integer, Change> changes, int start, int end) {
int size = 0;
Change[] range = new Change[end - start + 1];
@@ -1164,7 +1207,7 @@
}
private Account.Id createAccount(String name) throws Exception {
- return accountManager.authenticate(AuthRequest.forUser(name)).getAccountId();
+ return accountManager.authenticate(authRequestFactory.createForUser(name)).getAccountId();
}
@Test
@@ -1324,7 +1367,7 @@
TestRepository<Repo> repo = createProject("repo");
Change change = insert(repo, newChange(repo), userId);
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
for (int i = 0; i < 5; i++) {
insert(repo, newChange(repo), user2);
}
@@ -1337,7 +1380,7 @@
public void filterOutAllResults() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
for (int i = 0; i < 5; i++) {
insert(repo, newChange(repo), user2);
}
@@ -2123,11 +2166,11 @@
Account.Id user3 = createAccount("user3");
// Explicitly authenticate user2 and user3 so that display name gets set
- AuthRequest authRequest = AuthRequest.forUser("user2");
+ AuthRequest authRequest = authRequestFactory.createForUser("user2");
authRequest.setDisplayName("Another User");
authRequest.setEmailAddress("user2@example.com");
accountManager.authenticate(authRequest);
- authRequest = AuthRequest.forUser("user3");
+ authRequest = authRequestFactory.createForUser("user3");
authRequest.setDisplayName("Another User");
authRequest.setEmailAddress("user3@example.com");
accountManager.authenticate(authRequest);
@@ -2198,7 +2241,10 @@
Change change2 = insert(repo, newChange(repo));
int user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId().get();
+ accountManager
+ .authenticate(authRequestFactory.createForUser("anotheruser"))
+ .getAccountId()
+ .get();
ReviewInput input = new ReviewInput();
input.message = "toplevel";
@@ -2217,7 +2263,49 @@
}
@Test
- public void byDraftBy() throws Exception {
+ public void bySubmitRuleResult() throws Exception {
+ if (getSchemaVersion() < 68) {
+ assertMissingField(ChangeField.SUBMIT_RULE_RESULT);
+ return;
+ }
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(new FakeSubmitRule())) {
+ TestRepository<Repo> repo = createProject("repo");
+ Change change = insert(repo, newChange(repo));
+ assertQuery("rule:gerrit~FakeSubmitRule");
+
+ // FakeSubmitRule returns true if change has one or more hashtags.
+ HashtagsInput hashtag = new HashtagsInput();
+ hashtag.add = ImmutableSet.of("Tag1");
+ gApi.changes().id(change.getId().get()).setHashtags(hashtag);
+ assertQuery("rule:gerrit~FakeSubmitRule", change);
+ assertQuery("rule:gerrit~FakeSubmitRule=OK", change);
+ assertQuery("rule:gerrit~FakeSubmitRule=NOT_READY");
+
+ // The 'gerrit~' prefix can be omitted for core submit rules
+ assertQuery("rule:FakeSubmitRule", change);
+ }
+ }
+
+ @Test
+ public void byNonExistingSubmitRule_returnsEmpty() throws Exception {
+ // Some submit rules could be removed from the gerrit.config but there can be records for
+ // merged changes in NoteDb for these rules. We allow querying for non-existent rules to handle
+ // this case.
+ if (getSchemaVersion() < 68) {
+ assertMissingField(ChangeField.SUBMIT_RULE_RESULT);
+ return;
+ }
+ try (Registration registration =
+ extensionRegistry.newRegistration().add(new FakeSubmitRule())) {
+ TestRepository<Repo> repo = createProject("repo");
+ insert(repo, newChange(repo));
+ assertQuery("rule:non-existent-rule");
+ }
+ }
+
+ @Test
+ public void byHasDraft() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo));
Change change2 = insert(repo, newChange(repo));
@@ -2236,16 +2324,17 @@
in.path = Patch.COMMIT_MSG;
gApi.changes().id(change2.getId().get()).current().createDraft(in);
- int user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId().get();
+ Account.Id user2 =
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
assertQuery("has:draft", change2, change1);
- assertQuery("draftby:" + userId.get(), change2, change1);
- assertQuery("draftby:" + user2);
+
+ requestContext.setContext(newRequestContext(user2));
+ assertQuery("has:draft");
}
@Test
- public void byDraftByExcludesZombieDrafts() throws Exception {
+ public void byHasDraftExcludesZombieDrafts() throws Exception {
Project.NameKey project = Project.nameKey("repo");
TestRepository<Repo> repo = createProject(project.get());
Change change = insert(repo, newChange(repo));
@@ -2257,7 +2346,7 @@
in.path = Patch.COMMIT_MSG;
gApi.changes().id(id.get()).current().createDraft(in);
- assertQuery("draftby:" + userId, change);
+ assertQuery("has:draft", change);
assertQuery("commentby:" + userId);
try (TestRepository<Repo> allUsers =
@@ -2269,7 +2358,7 @@
rin.drafts = DraftHandling.PUBLISH_ALL_REVISIONS;
gApi.changes().id(id.get()).current().review(rin);
- assertQuery("draftby:" + userId);
+ assertQuery("has:draft");
assertQuery("commentby:" + userId, change);
assertThat(allUsers.getRepository().exactRef(draftsRef.getName())).isNull();
@@ -2279,7 +2368,7 @@
}
indexer.index(project, id);
- assertQuery("draftby:" + userId);
+ assertQuery("has:draft");
}
@Test
@@ -2292,69 +2381,62 @@
gApi.accounts().self().starChange(change1.getId().toString());
gApi.accounts().self().starChange(change2.getId().toString());
- int user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId().get();
+ Account.Id user2 =
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
- assertQuery("starredby:self", change2, change1);
- assertQuery("starredby:" + user2);
+ assertQuery("has:star", change2, change1);
+ assertQuery("star:star", change2, change1);
+
+ requestContext.setContext(newRequestContext(user2));
+ assertQuery("has:star");
+ assertQuery("star:star");
}
@Test
public void byStar() throws Exception {
TestRepository<Repo> repo = createProject("repo");
- Change change1 = insert(repo, newChange(repo));
+ Change change1 = insert(repo, newChangeWithStatus(repo, Change.Status.MERGED));
Change change2 = insert(repo, newChangeWithStatus(repo, Change.Status.MERGED));
- Change change3 = insert(repo, newChangeWithStatus(repo, Change.Status.MERGED));
- Change change4 = insert(repo, newChange(repo));
+ Change change3 = insert(repo, newChange(repo));
- gApi.accounts()
- .self()
- .setStars(
- change1.getId().toString(),
- new StarsInput(new HashSet<>(Arrays.asList("red", "blue"))));
- gApi.accounts()
- .self()
- .setStars(
- change2.getId().toString(),
- new StarsInput(
- new HashSet<>(Arrays.asList(StarredChangesUtil.DEFAULT_LABEL, "green", "blue"))));
+ Account.Id user2 =
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
+ requestContext.setContext(newRequestContext(user2));
- gApi.accounts()
- .self()
- .setStars(
- change4.getId().toString(), new StarsInput(new HashSet<>(Arrays.asList("ignore"))));
-
- // check labeled stars
- assertQuery("star:red", change1);
- assertQuery("star:blue", change2, change1);
- assertQuery("has:stars", change4, change2, change1);
+ gApi.accounts().self().starChange(change1.getId().toString());
+ gApi.changes().id(change3.getChangeId()).ignore(true);
// check default star
- assertQuery("has:star", change2);
- assertQuery("is:starred", change2);
- assertQuery("starredby:self", change2);
- assertQuery("star:" + StarredChangesUtil.DEFAULT_LABEL, change2);
+ assertQuery("has:star", change1);
+ assertQuery("is:starred", change1);
+ assertQuery("star:" + StarredChangesUtil.DEFAULT_LABEL, change1);
// check ignored
- assertQuery("is:ignored", change4);
- assertQuery("-is:ignored", change3, change2, change1);
+ assertQuery("is:ignored", change3);
+ assertQuery("-is:ignored", change2, change1);
+ assertQuery("star:ignore", change3);
+ assertQuery("-star:ignore", change2, change1);
}
@Test
public void byIgnore() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change1 = insert(repo, newChange(repo), user2);
Change change2 = insert(repo, newChange(repo), user2);
gApi.changes().id(change1.getId().toString()).ignore(true);
assertQuery("is:ignored", change1);
assertQuery("-is:ignored", change2);
+ assertQuery("star:ignore", change1);
+ assertQuery("-star:ignore", change2);
gApi.changes().id(change1.getId().toString()).ignore(false);
assertQuery("is:ignored");
assertQuery("-is:ignored", change2, change1);
+ assertQuery("star:ignore");
+ assertQuery("-star:ignore", change2, change1);
}
@Test
@@ -2363,7 +2445,7 @@
Change change1 = insert(repo, newChange(repo));
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change2 = insert(repo, newChange(repo), user2);
ReviewInput input = new ReviewInput();
@@ -2434,6 +2516,17 @@
}
@Test
+ public void cherrypick() throws Exception {
+ assume().that(getSchema().hasField(ChangeField.CHERRY_PICK)).isTrue();
+ TestRepository<Repo> repo = createProject("repo");
+ Change change1 = insert(repo, newChange(repo));
+ Change change2 = insert(repo, newCherryPickChange(repo, "foo", change1.currentPatchSetId()));
+
+ assertQuery("is:cherrypick", change2);
+ assertQuery("-is:cherrypick", change1);
+ }
+
+ @Test
public void merge() throws Exception {
assume().that(getSchema().hasField(ChangeField.MERGE)).isTrue();
TestRepository<Repo> repo = createProject("repo");
@@ -2470,7 +2563,7 @@
gApi.changes().id(change1.getId().get()).current().review(new ReviewInput().message("comment"));
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
requestContext.setContext(newRequestContext(user2));
gApi.changes().id(change2.getId().get()).current().review(new ReviewInput().message("comment"));
@@ -2536,7 +2629,7 @@
public void byReviewed() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Account.Id otherUser =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
Change change1 = insert(repo, newChange(repo));
Change change2 = insert(repo, newChange(repo));
@@ -2556,9 +2649,12 @@
@Test
public void reviewerin() throws Exception {
- Account.Id user1 = accountManager.authenticate(AuthRequest.forUser("user1")).getAccountId();
- Account.Id user2 = accountManager.authenticate(AuthRequest.forUser("user2")).getAccountId();
- Account.Id user3 = accountManager.authenticate(AuthRequest.forUser("user3")).getAccountId();
+ Account.Id user1 =
+ accountManager.authenticate(authRequestFactory.createForUser("user1")).getAccountId();
+ Account.Id user2 =
+ accountManager.authenticate(authRequestFactory.createForUser("user2")).getAccountId();
+ Account.Id user3 =
+ accountManager.authenticate(authRequestFactory.createForUser("user3")).getAccountId();
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo));
@@ -2835,7 +2931,6 @@
insert(repo2, ins2);
assertQuery("is:watched");
- assertQuery("watchedby:self");
List<ProjectWatchInfo> projectsToWatch = new ArrayList<>();
ProjectWatchInfo pwi = new ProjectWatchInfo();
@@ -2849,7 +2944,6 @@
resetUser();
assertQuery("is:watched", change1);
- assertQuery("watchedby:self", change1);
}
@Test
@@ -2875,19 +2969,6 @@
}
@Test
- public void selfAndMe() throws Exception {
- TestRepository<Repo> repo = createProject("repo");
- Change change1 = insert(repo, newChange(repo));
- Change change2 = insert(repo, newChange(repo), userId);
- insert(repo, newChange(repo));
- gApi.accounts().self().starChange(change1.getId().toString());
- gApi.accounts().self().starChange(change2.getId().toString());
-
- assertQuery("starredby:self", change2, change1);
- assertQuery("starredby:me", change2, change1);
- }
-
- @Test
public void defaultFieldWithManyUsers() throws Exception {
for (int i = 0; i < ChangeQueryBuilder.MAX_ACCOUNTS_PER_DEFAULT_FIELD * 2; i++) {
createAccount("user" + i, "User " + i, "user" + i + "@example.com", true);
@@ -3021,8 +3102,7 @@
}
for (Account.Id ignorerId : ignoredBy) {
requestContext.setContext(newRequestContext(ignorerId));
- StarsInput in = new StarsInput(new HashSet<>(Arrays.asList("ignore")));
- gApi.accounts().self().setStars("" + id, in);
+ gApi.changes().id(change.getChangeId()).ignore(true);
}
DraftInput in = new DraftInput();
in.path = Patch.COMMIT_MSG;
@@ -3352,6 +3432,7 @@
@Test
public void attentionSetIndexed() throws Exception {
assume().that(getSchema().hasField(ChangeField.ATTENTION_SET_USERS)).isTrue();
+ assume().that(getSchema().hasField(ChangeField.ATTENTION_SET_USERS_COUNT)).isTrue();
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChange(repo));
Change change2 = insert(repo, newChange(repo));
@@ -3359,8 +3440,18 @@
AttentionSetInput input = new AttentionSetInput(userId.toString(), "some reason");
gApi.changes().id(change1.getChangeId()).addToAttentionSet(input);
+ assertQuery("is:attention", change1);
+ assertQuery("-is:attention", change2);
+ assertQuery("has:attention", change1);
+ assertQuery("-has:attention", change2);
assertQuery("attention:" + user.getUserName().get(), change1);
assertQuery("-attention:" + userId.toString(), change2);
+
+ gApi.changes()
+ .id(change1.getChangeId())
+ .attention(userId.toString())
+ .remove(new AttentionSetInput("removed again"));
+ assertQuery("-is:attention", change1, change2);
}
@Test
@@ -3372,7 +3463,7 @@
AttentionSetInput input = new AttentionSetInput(userId.toString(), "reason 1");
gApi.changes().id(change.getChangeId()).addToAttentionSet(input);
Account.Id user2Id =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
// Add the second user as cc to ensure that user took part of the change and can be added to the
// attention set.
@@ -3424,7 +3515,7 @@
.isEqualTo("Unknown named destination: foo");
Account.Id anotherUserId =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
String destination1 = "refs/heads/master\trepo1";
String destination2 = "refs/heads/master\trepo2";
String destination3 = "refs/heads/master\trepo1\nrefs/heads/master\trepo2";
@@ -3501,7 +3592,7 @@
Change change2 = insert(repo, newChangeForBranch(repo, "stable"));
Account.Id anotherUserId =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
String queryListText =
"query1\tproject:repo\n"
+ "query2\tproject:repo status:open\n"
@@ -3585,7 +3676,7 @@
@Test
public void selfFailsForAnonymousUser() throws Exception {
- for (String query : ImmutableList.of("assignee:self", "starredby:self", "is:starred")) {
+ for (String query : ImmutableList.of("assignee:self", "has:star", "is:starred", "star:star")) {
assertQuery(query);
RequestContext oldContext = requestContext.setContext(anonymousUserProvider::get);
@@ -3603,22 +3694,20 @@
@Test
public void selfSucceedsForInactiveAccount() throws Exception {
Account.Id user2 =
- accountManager.authenticate(AuthRequest.forUser("anotheruser")).getAccountId();
+ accountManager.authenticate(authRequestFactory.createForUser("anotheruser")).getAccountId();
TestRepository<Repo> repo = createProject("repo");
Change change = insert(repo, newChange(repo));
- AssigneeInput ain = new AssigneeInput();
- ain.assignee = user2.toString();
- gApi.changes().id(change.getId().get()).setAssignee(ain);
+ gApi.changes().id(change.getId().get()).addReviewer(user2.toString());
RequestContext adminContext = requestContext.setContext(newRequestContext(user2));
- assertQuery("assignee:self", change);
+ assertQuery("reviewer:self", change);
requestContext.setContext(adminContext);
gApi.accounts().id(user2.get()).setActive(false);
requestContext.setContext(newRequestContext(user2));
- assertQuery("assignee:self", change);
+ assertQuery("reviewer:self", change);
}
@Test
@@ -3657,12 +3746,12 @@
}
protected ChangeInserter newChange(TestRepository<Repo> repo) throws Exception {
- return newChange(repo, null, null, null, null, false, false);
+ return newChange(repo, null, null, null, null, null, false, false);
}
protected ChangeInserter newChangeForCommit(TestRepository<Repo> repo, RevCommit commit)
throws Exception {
- return newChange(repo, commit, null, null, null, false, false);
+ return newChange(repo, commit, null, null, null, null, false, false);
}
protected ChangeInserter newChangeWithFiles(TestRepository<Repo> repo, String... paths)
@@ -3676,25 +3765,30 @@
protected ChangeInserter newChangeForBranch(TestRepository<Repo> repo, String branch)
throws Exception {
- return newChange(repo, null, branch, null, null, false, false);
+ return newChange(repo, null, branch, null, null, null, false, false);
}
protected ChangeInserter newChangeWithStatus(TestRepository<Repo> repo, Change.Status status)
throws Exception {
- return newChange(repo, null, null, status, null, false, false);
+ return newChange(repo, null, null, status, null, null, false, false);
}
protected ChangeInserter newChangeWithTopic(TestRepository<Repo> repo, String topic)
throws Exception {
- return newChange(repo, null, null, null, topic, false, false);
+ return newChange(repo, null, null, null, topic, null, false, false);
}
protected ChangeInserter newChangeWorkInProgress(TestRepository<Repo> repo) throws Exception {
- return newChange(repo, null, null, null, null, true, false);
+ return newChange(repo, null, null, null, null, null, true, false);
}
protected ChangeInserter newChangePrivate(TestRepository<Repo> repo) throws Exception {
- return newChange(repo, null, null, null, null, false, true);
+ return newChange(repo, null, null, null, null, null, false, true);
+ }
+
+ protected ChangeInserter newCherryPickChange(
+ TestRepository<Repo> repo, String branch, PatchSet.Id cherryPickOf) throws Exception {
+ return newChange(repo, null, branch, null, null, cherryPickOf, false, true);
}
protected ChangeInserter newChange(
@@ -3703,6 +3797,7 @@
@Nullable String branch,
@Nullable Change.Status status,
@Nullable String topic,
+ @Nullable PatchSet.Id cherryPickOf,
boolean workInProgress,
boolean isPrivate)
throws Exception {
@@ -3723,7 +3818,8 @@
.setStatus(status)
.setTopic(topic)
.setWorkInProgress(workInProgress)
- .setPrivate(isPrivate);
+ .setPrivate(isPrivate)
+ .setCherryPickOf(cherryPickOf);
return ins;
}
@@ -3976,9 +4072,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/javatests/com/google/gerrit/server/query/change/BUILD b/javatests/com/google/gerrit/server/query/change/BUILD
index 0f102a8..08456d1 100644
--- a/javatests/com/google/gerrit/server/query/change/BUILD
+++ b/javatests/com/google/gerrit/server/query/change/BUILD
@@ -17,6 +17,7 @@
"//prolog:gerrit-prolog-common",
],
deps = [
+ "//java/com/google/gerrit/acceptance:lib",
"//java/com/google/gerrit/acceptance/config",
"//java/com/google/gerrit/acceptance/testsuite/project",
"//java/com/google/gerrit/common:annotations",
diff --git a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
index f392747..568b5a0 100644
--- a/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/AbstractQueryGroupsTest.java
@@ -106,6 +106,8 @@
@Inject protected GroupIndexCollection indexes;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
@Inject private GroupIndexCollection groupIndexes;
protected LifecycleManager lifecycle;
@@ -397,9 +399,10 @@
private Account.Id createAccountOutsideRequestContext(
String username, String fullName, String email, boolean active) throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
index 2317c7e..60d1655 100644
--- a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
@@ -104,6 +104,8 @@
@Inject protected AllUsersName allUsers;
+ @Inject protected AuthRequest.Factory authRequestFactory;
+
protected LifecycleManager lifecycle;
protected Injector injector;
protected AccountInfo currentUserInfo;
@@ -309,9 +311,10 @@
private Account.Id createAccount(String username, String fullName, String email, boolean active)
throws Exception {
try (ManualRequestContext ctx = oneOffRequestContext.open()) {
- Account.Id id = accountManager.authenticate(AuthRequest.forUser(username)).getAccountId();
+ Account.Id id =
+ accountManager.authenticate(authRequestFactory.createForUser(username)).getAccountId();
if (email != null) {
- accountManager.link(id, AuthRequest.forEmail(email));
+ accountManager.link(id, authRequestFactory.createForEmail(email));
}
accountsUpdate
.get()
diff --git a/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
index da22f76..e0ba666 100644
--- a/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
+++ b/javatests/com/google/gerrit/server/schema/ProjectConfigSchemaUpdateTest.java
@@ -19,6 +19,7 @@
import com.google.common.collect.ImmutableList;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.config.AllProjectsName;
+import com.google.gerrit.server.config.FileBasedAllProjectsConfigProvider;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -36,7 +37,10 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+@RunWith(JUnit4.class)
public class ProjectConfigSchemaUpdateTest {
private static final String ALL_PROJECTS = "All-The-Projects";
@@ -64,8 +68,11 @@
try (Repository repo = new FileRepository(allProjectsRepoFile)) {
repo.create(true);
}
+ FileBasedAllProjectsConfigProvider configProvider =
+ new FileBasedAllProjectsConfigProvider(sitePaths);
- factory = new ProjectConfigSchemaUpdate.Factory(sitePaths, new AllProjectsName(ALL_PROJECTS));
+ factory =
+ new ProjectConfigSchemaUpdate.Factory(new AllProjectsName(ALL_PROJECTS), configProvider);
}
@Test
diff --git a/package.json b/package.json
index 9df72da..a47ba9f 100644
--- a/package.json
+++ b/package.json
@@ -6,19 +6,20 @@
"@bazel/rollup": "^3.5.0",
"@bazel/terser": "^3.5.0",
"@bazel/typescript": "^3.5.0",
- "twinkie": "^1.1.2"
+ "twinkie": "^1.1.3"
},
"devDependencies": {
- "@typescript-eslint/eslint-plugin": "^4.25.0",
+ "@typescript-eslint/eslint-plugin": "^4.29.0",
"eslint": "^7.24.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsdoc": "^32.3.0",
+ "eslint-plugin-lit": "^1.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^3.4.0",
+ "eslint-plugin-regex": "^1.8.0",
"gts": "^3.1.0",
- "polymer-cli": "^1.9.11",
"prettier": "2.3.1",
"rollup": "^2.45.2",
"terser": "^5.6.1",
@@ -33,17 +34,19 @@
"safe_bazelisk": "if which bazelisk >/dev/null; then bazel_bin=bazelisk; else bazel_bin=bazel; fi && $bazel_bin",
"eslint": "npm run safe_bazelisk test polygerrit-ui/app:lint_test",
"eslintfix": "npm run safe_bazelisk run polygerrit-ui/app:lint_bin -- -- --fix $(pwd)/polygerrit-ui/app",
- "polylint": "npm run safe_bazelisk test polygerrit-ui/app:polylint_test",
- "test:debug": "npm run compile:local && npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --browsers ChromeDev --no-single-run --testFiles",
- "test:single": "npm run compile:local && npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --testFiles",
- "postinstall": "(git apply --reverse --ignore-whitespace twinkie.patch || true) && git apply --ignore-whitespace twinkie.patch",
- "polytest": "npm run safe_bazelisk test //polygerrit-ui/app:validate_polymer_templates",
- "polytest:dev": "rm -rf ./polygerrit-ui/app/tmpl_out && npm run safe_bazelisk build //polygerrit-ui/app:template_test_tar && mkdir ./polygerrit-ui/app/tmpl_out && tar -xf bazel-bin/polygerrit-ui/app/template_test_tar.tar -C ./polygerrit-ui/app/tmpl_out"
+ "test:debug": "npm run compile:local && npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --root '.ts-out/polygerrit-ui/app/' --browsers ChromeDev --no-single-run --test-files",
+ "test:single": "npm run compile:local && npm run safe_bazelisk run //polygerrit-ui:karma_bin -- -- start $(pwd)/polygerrit-ui/karma.conf.js --root '.ts-out/polygerrit-ui/app/' --test-files",
+ "polylint": "npm run safe_bazelisk test //polygerrit-ui/app:polylint_test",
+ "polylint:dev": "rm -rf ./polygerrit-ui/app/tmpl_out && npm run safe_bazelisk build //polygerrit-ui/app:template_test_tar && mkdir ./polygerrit-ui/app/tmpl_out && tar -xf bazel-bin/polygerrit-ui/app/template_test_tar.tar -C ./polygerrit-ui/app/tmpl_out"
},
"repository": {
"type": "git",
"url": "https://gerrit.googlesource.com/gerrit"
},
+ "resolutions": {
+ "lodash": "4.17.21",
+ "twinkie/typescript": "4.3.2"
+ },
"author": "",
"license": "Apache-2.0"
}
diff --git a/plugins/delete-project b/plugins/delete-project
index 7dce6f7..8fe544a 160000
--- a/plugins/delete-project
+++ b/plugins/delete-project
@@ -1 +1 @@
-Subproject commit 7dce6f70611cd8dbf1d38628698155258ee8ef82
+Subproject commit 8fe544ac569efa357ee054257143d8e1d4aa6afd
diff --git a/plugins/package.json b/plugins/package.json
index f761be9..4e3c376 100644
--- a/plugins/package.json
+++ b/plugins/package.json
@@ -5,7 +5,7 @@
"dependencies": {
"@polymer/decorators": "^3.0.0",
"@polymer/polymer": "^3.4.1",
- "@gerritcodereview/typescript-api": "3.4.2",
+ "@gerritcodereview/typescript-api": "3.4.4",
"lit": "2.0.0-rc.3"
},
"license": "Apache-2.0",
diff --git a/plugins/replication b/plugins/replication
index 46cfb7d..cd17fe7 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 46cfb7dd5b6891f991cfe66e72c08953487c1c81
+Subproject commit cd17fe7f90e5a36ab84b9b7ce0aab22e60e48a70
diff --git a/plugins/tsconfig-plugins-base.json b/plugins/tsconfig-plugins-base.json
index b9d14e1..b7e9d52 100644
--- a/plugins/tsconfig-plugins-base.json
+++ b/plugins/tsconfig-plugins-base.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
/* Basic Options */
- "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"inlineSourceMap": true, /* Generates corresponding '.map' file. */
"rootDir": ".", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
@@ -20,6 +20,7 @@
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ "noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,/* Report errors for fallthrough cases in switch statement. */
"skipLibCheck": true, /* Do not check node_modules */
@@ -34,6 +35,15 @@
"incremental": true,
"experimentalDecorators": true,
- "allowUmdGlobalAccess": true
+ "allowUmdGlobalAccess": true,
+
+ "typeRoots": [
+ /* typeRoots for Bazel */
+ "../external/ui_dev_npm/node_modules/@types",
+ "../external/plugins_npm/node_modules/@types",
+ /* typeRoots for IDE */
+ "../polygerrit-ui/node_modules/@types",
+ "../plugins/node_modules/@types"
+ ]
},
}
diff --git a/plugins/yarn.lock b/plugins/yarn.lock
index 1faa71a..3ff1cc4 100644
--- a/plugins/yarn.lock
+++ b/plugins/yarn.lock
@@ -2,10 +2,10 @@
# yarn lockfile v1
-"@gerritcodereview/typescript-api@3.4.2":
- version "3.4.2"
- resolved "https://registry.yarnpkg.com/@gerritcodereview/typescript-api/-/typescript-api-3.4.2.tgz#79e8ff336608cbf18e651bfa9541d7bdead5e1f9"
- integrity sha512-iqHd6G43pV4Wk5iNw95AQmWUBuIrY+dvQ1Ne8ZYkOwRhdruh4BAPhMtsmqWDlcVQbfcwZD5F2zFkGB4J4htggw==
+"@gerritcodereview/typescript-api@3.4.4":
+ version "3.4.4"
+ resolved "https://registry.yarnpkg.com/@gerritcodereview/typescript-api/-/typescript-api-3.4.4.tgz#9f09687038088dd7edd3b4e30d249502eb21bfbc"
+ integrity sha512-MAiQwntcQ59b92yYDsVIXj3oBbAB4C7HELkLFFbYs4ZjzC43XqqtR9VF0dh5OUC8wzFZttgUiOmGehk9edpPuw==
"@lit/reactive-element@^1.0.0-rc.2":
version "1.0.0-rc.2"
diff --git a/polygerrit-ui/BUILD b/polygerrit-ui/BUILD
index 7bca96d..62d1d92 100644
--- a/polygerrit-ui/BUILD
+++ b/polygerrit-ui/BUILD
@@ -1,5 +1,6 @@
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
load("//tools/bzl:genrule2.bzl", "genrule2")
+load("//tools/bzl:js.bzl", "karma_test")
package(default_visibility = ["//visibility:public"])
@@ -33,8 +34,6 @@
],
)
-# Define a karma+plugins binary to run karma-mocha tests.
-# Can be reused multiple time, if there are multiple karma test rules
sh_binary(
name = "karma_bin",
srcs = ["@ui_dev_npm//:node_modules/karma/bin/karma"],
@@ -49,26 +48,8 @@
],
)
-# Run all tests in one.
-# TODO(dmfilippov): allow parallel tests for karma - either on the bazel level
-# or on the karma level. For now single sh_test is enough.
-sh_test(
+karma_test(
name = "karma_test",
- size = "enormous",
srcs = ["karma_test.sh"],
- args = [
- "$(location :karma_bin)",
- "$(location karma.conf.js)",
- ],
- data = [
- "karma.conf.js",
- ":karma_bin",
- "//polygerrit-ui/app:test-srcs-fg",
- ],
- # Should not run sandboxed.
- tags = [
- "karma",
- "local",
- "manual",
- ],
+ data = ["//polygerrit-ui/app:test-srcs-fg"],
)
diff --git a/polygerrit-ui/app/.eslintrc.js b/polygerrit-ui/app/.eslintrc.js
index faf126c..14f9e8c 100644
--- a/polygerrit-ui/app/.eslintrc.js
+++ b/polygerrit-ui/app/.eslintrc.js
@@ -277,6 +277,18 @@
},
},
{
+ files: ['**/api/*.ts'],
+ rules: {
+ 'regex/invalid': [
+ 'error', [{
+ regex: 'export interface',
+ message: 'All interfaces in the api/ dir must have "declare"',
+ replacement: 'export declare interface',
+ }],
+ ],
+ },
+ },
+ {
files: ['**/*.ts'],
extends: [require.resolve('gts/.eslintrc.json')],
rules: {
@@ -400,12 +412,32 @@
}],
},
},
+ {
+ files: ['*.ts'],
+ excludedFiles: '*_html.ts',
+ rules: {
+ 'lit/attribute-value-entities': 'error',
+ 'lit/binding-positions': 'error',
+ 'lit/no-duplicate-template-bindings': 'error',
+ 'lit/no-invalid-html': 'error',
+ 'lit/no-legacy-template-syntax': 'error',
+ 'lit/no-property-change-update': 'error',
+ 'lit/no-invalid-escape-sequences': 'error',
+ 'lit/no-legacy-imports': 'error',
+ 'lit/no-private-properties': 'error',
+ 'lit/no-useless-template-literals': 'error',
+ 'lit/no-value-attribute': 'error',
+ 'lit/prefer-static-styles': 'error',
+ },
+ },
],
plugins: [
'html',
'jsdoc',
'import',
+ 'lit',
'prettier',
+ 'regex',
],
settings: {
'html/report-bad-indent': 'error',
diff --git a/polygerrit-ui/app/BUILD b/polygerrit-ui/app/BUILD
index 4a186c1..0552d45 100644
--- a/polygerrit-ui/app/BUILD
+++ b/polygerrit-ui/app/BUILD
@@ -45,8 +45,6 @@
),
allow_js = True,
incremental = True,
- # The same outdir also appears in the following files:
- # polylint_test.sh
out_dir = "_pg_ts_out",
tsc = "//tools/node_tools:tsc-bin",
tsconfig = ":ts_config_bazel",
@@ -70,7 +68,6 @@
[
"**/*.js",
"**/*.ts",
- "test/@types/*.d.ts",
],
exclude = [
"node_modules/**",
@@ -97,9 +94,7 @@
# so template tests pass.
# TODO: fix problems reported by template checker in these files.
ignore_templates_list = [
- "elements/admin/gr-access-section/gr-access-section_html.ts",
"elements/admin/gr-admin-view/gr-admin-view_html.ts",
- "elements/admin/gr-create-change-dialog/gr-create-change-dialog_html.ts",
"elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts",
"elements/admin/gr-group-members/gr-group-members_html.ts",
"elements/admin/gr-group/gr-group_html.ts",
@@ -110,7 +105,6 @@
"elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_html.ts",
"elements/admin/gr-repo/gr-repo_html.ts",
"elements/admin/gr-rule-editor/gr-rule-editor_html.ts",
- "elements/change-list/gr-change-list-item/gr-change-list-item_html.ts",
"elements/change-list/gr-change-list-view/gr-change-list-view_html.ts",
"elements/change-list/gr-change-list/gr-change-list_html.ts",
"elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts",
@@ -118,9 +112,6 @@
"elements/change/gr-change-metadata/gr-change-metadata_html.ts",
"elements/change/gr-change-requirements/gr-change-requirements_html.ts",
"elements/change/gr-change-view/gr-change-view_html.ts",
- "elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_html.ts",
- "elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts",
- "elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts",
"elements/change/gr-file-list-header/gr-file-list-header_html.ts",
"elements/change/gr-file-list/gr-file-list_html.ts",
"elements/change/gr-label-score-row/gr-label-score-row_html.ts",
@@ -146,17 +137,19 @@
"elements/shared/gr-list-view/gr-list-view_html.ts",
]
+sources_for_template_checking = glob(
+ [src_dir + "/**/*" + ext for src_dir in src_dirs for ext in [
+ ".ts",
+ ]],
+ exclude = [
+ "**/*_test.ts",
+ ] + ignore_templates_list,
+)
+
# Transform templates into a .ts files.
templates_srcs = transform_polymer_templates(
name = "template_test",
- srcs = glob(
- [src_dir + "/**/*" + ext for src_dir in src_dirs for ext in [
- ".ts",
- ]],
- exclude = [
- "**/*_test.ts",
- ] + ignore_templates_list,
- ),
+ srcs = sources_for_template_checking,
out_tsconfig = "tsconfig_template_test.json",
tsconfig = "tsconfig_bazel.json",
deps = [
@@ -166,50 +159,34 @@
],
)
-# Compile transformed templates together with the polygerrit source. If
-# templates don't have problem, then the compilation ends without error.
-# Otherwise, the typescript compiler reports the error.
-# Note, that the compile_ts macro creates build rules. If the build succeed,
-# the macro creates the file compile_template_test.success. The
-# 'validate_polymer_templates' rule tests existence of the file.
-#
-# TODO: Re-instantiate this rule. It broke when switching to ts_project with
-# ERROR: //polygerrit-ui/app:compile_template_test srcs cannot be a mix of
-# generated files and source files since this would prevent giving a
-# single rootDir to the TypeScript compiler
-# Also, the emitJS feature of compile_ts has to be re-created in some form.
-#ts_project(
-# name = "compile_template_test",
-# srcs = templates_srcs + glob(
-# [src_dir + "/**/*" + ext for src_dir in src_dirs for ext in [
-# ".ts",
-# ]],
-# exclude = [
-# "**/*_test.ts",
-# ] + ignore_templates_list,
-# ),
-# allow_js = True,
-# out_dir = "_pg_template_test_out",
-# # Should not run sandboxed.
-# tags = [
-# "local",
-# "manual",
-# ],
-# tsc = "//tools/node_tools:tsc-bin",
-# tsconfig = "tsconfig_template_test.json",
-#)
-#
-# This rule allows to run polymer template checker with bazel test command.
-# For details - see compile_template_test rule.
-#
-# TODO: Re-instantiate this test. It broke when switching
-# 'compile_template_test'to ts_project, see above. ts_project does not
-# create '.success' files.
-#sh_test(
-# name = "validate_polymer_templates",
-# srcs = [":empty_test.sh"],
-# data = ["compile_template_test.success"],
-#)
+# After templates are converted into a typescript code, the TS compiler should check that the
+# converted code doesn't have the error (i.e. templates don't have problems).
+# The input to the compiler is: the converted (i.e. autogenerated) code + original polygerrit code;
+# the output (i.e. js code) is not needed (we only care wheather the code has error or not).
+# The existing ts_project rule can't compile a mix of a generated and a non-generated code, so it
+# can't be used for the purpose of template checking.
+# Because the output of TS compiler is not needed, the simplest workaround is to run typescript
+# compiler from command line using the sh_test rule. The compiler exits with non-zero return code if
+# errors found and sh_test fails.
+sh_test(
+ name = "polylint_test",
+ srcs = [":compile_generated_templates.sh"],
+ args = [
+ "$(location //tools/node_tools:tsc-bin)",
+ "$(location tsconfig_template_test.json)",
+ ],
+ data = [
+ "tsconfig_template_test.json",
+ "tsconfig_bazel.json",
+ "tsconfig.json",
+ "//tools/node_tools:tsc-bin",
+ "@ui_npm//:node_modules",
+ ] + templates_srcs + sources_for_template_checking,
+ tags = [
+ "local",
+ "manual",
+ ],
+)
polygerrit_bundle(
name = "polygerrit_ui",
@@ -291,33 +268,3 @@
"@npm//gts",
],
)
-
-filegroup(
- name = "polylint-fg",
- srcs = [
- # Workaround for https://github.com/bazelbuild/bazel/issues/1305
- "@ui_npm//:node_modules",
- # Polylinter can't check .ts files, run it on compiled srcs
- ":compile_pg",
- ],
-)
-
-sh_test(
- name = "polylint_test",
- size = "large",
- srcs = ["polylint_test.sh"],
- args = [
- "$(location @tools_npm//polymer-cli/bin:polymer)",
- "$(location polymer.json)",
- ],
- data = [
- "polymer.json",
- ":polylint-fg",
- "@tools_npm//polymer-cli/bin:polymer",
- ],
- # Should not run sandboxed.
- tags = [
- "local",
- "manual",
- ],
-)
diff --git a/polygerrit-ui/app/api/BUILD_for_publishing_api_only b/polygerrit-ui/app/api/BUILD_for_publishing_api_only
new file mode 100644
index 0000000..9d3029b
--- /dev/null
+++ b/polygerrit-ui/app/api/BUILD_for_publishing_api_only
@@ -0,0 +1,50 @@
+# This BUILD file is only for publishing the
+# "Gerrit Frontend Plugin TypeScript API" as an npm package.
+#
+# Publishing procedure:
+# - Execute the `publish.sh` script from the Gerrit root dir.
+# - Verify that the contents look good.
+# - Increment the version in package.json.
+# - Execute `publish.sh --upload`.
+#
+# NB: Renaming to 'BUILD' breaks the app/BUILD, because then the api/ sources
+# are not visible anymore to the parent BUILD. And if ts_projects depend on each
+# other, then the api/ files would have to be imported with their full package
+# names.
+load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm")
+load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
+
+filegroup(
+ name = "js_plugin_api_srcs",
+ srcs = glob(["**/*.ts"]),
+)
+
+ts_config(
+ name = "ts_config",
+ src = "tsconfig.json",
+ deps = [
+ "//plugins:tsconfig-plugins-base.json",
+ ],
+)
+
+ts_project(
+ name = "js_plugin_api_compiled",
+ srcs = glob(["**/*.ts"]),
+ incremental = True,
+ tsc = "//tools/node_tools:tsc-bin",
+ tsconfig = ":ts_config",
+)
+
+# Use this rule for publishing the js plugin api as a package to the npm repo.
+pkg_npm(
+ name = "js_plugin_api_npm_package",
+ srcs = glob(
+ ["**/*"],
+ exclude = [
+ "BUILD",
+ "tsconfig.json",
+ "publish.sh",
+ ],
+ ),
+ deps = [":js_plugin_api_compiled"],
+)
diff --git a/polygerrit-ui/app/api/README.md b/polygerrit-ui/app/api/README.md
index 550063f..b5710bf 100644
--- a/polygerrit-ui/app/api/README.md
+++ b/polygerrit-ui/app/api/README.md
@@ -1,23 +1,25 @@
-# API
+# Gerrit TypeScript Plugin API
-In this folder, we declare the API of various parts of the Gerrit webclient.
-There are two primary use cases for this:
+This package contains the types for developing browser plugins for the
+Gerrit Code Review web application. General documentation for plugin
+developers can be found at
+[gerrit-review.googlesource.com](https://gerrit-review.googlesource.com/Documentation/pg-plugin-dev.html).
-* apps that embed our diff viewer, gr-diff
-* Gerrit plugins that need to access some part of Gerrit to extend it
+The `.ts` files only contain types, interfaces and enums, and thus the compiled
+`.js` files only contain the enums. For JavaScript plugins this package is not
+really useful or necessary, but it also serves as the source of truth for
+what plugin APIs are actually supported.
-Both may be built as a separate bundle, but would like to type check against
-the same types the Gerrit/gr-diff bundle uses. For this reason, this folder
-should contain only types, with the exception of enums, where having the
-value side is deemed an acceptable duplication.
+Versioning of this API matches the MAJOR and MINOR versions of the general
+Gerrit releases, but the PATCH version is independent. When you are building
+a plugin for Gerrit x.y.z, then you should use the API package x.y.n, where
+n is the highest available patch version of the API. Patch versions will only
+contain additions and fixes, minor versions may include API removals.
All types in here should use the `declare` keyword to prevent bundlers from
renaming fields, which would break communication across separately built
-bundles. Again enums are the exception, because their keys are not referenced
+bundles. enums are the exception, because their keys are not referenced
across bundles, and values will not be renamed by bundlers as they are strings.
-This API is used by other apps embedding gr-diff and any breaking changes
+This API is also used by other apps embedding gr-diff and any breaking changes
should be discussed with the Gerrit core team and properly versioned.
-
-Gerrit types should either directly use or extend these types, so that
-breaking changes to the implementation require changes to these files.
diff --git a/polygerrit-ui/app/api/change-actions.ts b/polygerrit-ui/app/api/change-actions.ts
index 2ce697a..4380195 100644
--- a/polygerrit-ui/app/api/change-actions.ts
+++ b/polygerrit-ui/app/api/change-actions.ts
@@ -72,6 +72,9 @@
export type PrimaryActionKey = ChangeActions | RevisionActions;
export declare interface ChangeActionsPluginApi {
+ // Deprecated. This API method will be removed.
+ ensureEl(): Element;
+
addPrimaryActionKey(key: PrimaryActionKey): void;
removePrimaryActionKey(key: string): void;
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index b64cd91..d52a555 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -144,8 +144,8 @@
* attempt. Every run has its own attempt numbering, so attempt 3 of run A is
* not directly related to attempt 3 of run B.
*
- * RUNNABLE runs must use `undefined` as attempt.
- * COMPLETED and RUNNING runs must use an attempt number >=0.
+ * The attempt number must be >=0. Only if you have just one RUNNABLE attempt,
+ * then you can leave it undefined.
*
* TBD: Optionally providing aggregate information about former attempts will
* probably be a useful feature, but we are deferring the exact data modeling
@@ -184,7 +184,8 @@
/**
* RUNNABLE: Not run (yet). Mostly useful for runs that the user can trigger
- * (see actions). Cannot contain results.
+ * (see actions) and for indicating that a check was not run at a
+ * later attempt. Cannot contain results.
* RUNNING: Subsumes "scheduled".
* COMPLETED: The attempt of the run has finished. Does not indicate at all
* whether the run was successful or not. Outcomes can and should
@@ -249,6 +250,12 @@
*/
primary?: boolean;
/**
+ * Summary actions will get an even more prominent treatment in the UI. They
+ * will show up in the checks summary right below the commit message. This
+ * only affects top-level actions (i.e. actions in FetchResponse).
+ */
+ summary?: boolean;
+ /**
* Renders the action button in a disabled state. That can be useful for
* actions that are present most of the time, but sometimes don't apply. Then
* a grayed out button with a tooltip makes it easier for the user to
diff --git a/polygerrit-ui/app/api/diff.ts b/polygerrit-ui/app/api/diff.ts
index ba7eb70..ee579ff 100644
--- a/polygerrit-ui/app/api/diff.ts
+++ b/polygerrit-ui/app/api/diff.ts
@@ -53,30 +53,30 @@
}
/**
+ * Represents a "generic" text range in the code (e.g. text selection)
+ */
+interface TextRange {
+ /** first line of the range (1-based inclusive). */
+ start_line: number;
+ /** first column of the range (in the first line) (1-based inclusive). */
+ start_column: number;
+ /** last line of the range (1-based inclusive). */
+ end_line: number;
+ /** last column of the range (in the end line) (1-based inclusive). */
+ end_column: number;
+}
+
+/**
* Represents a syntax block in a code (e.g. method, function, class, if-else).
*/
export declare interface SyntaxBlock {
/** Name of the block (e.g. name of the method/class)*/
name: string;
- /** Where does this block syntatically starts and ends (line number and column).*/
- range: {
- /** first line of the block (1-based inclusive). */
- start_line: number;
- /**
- * column of the range start inside the first line (e.g. "{" character ending a function/method)
- * (1-based inclusive).
- */
- start_column: number;
- /**
- * last line of the block (1-based inclusive).
- */
- end_line: number;
- /**
- * column of the block end inside the end line (e.g. "}" character ending a function/method)
- * (1-based inclusive).
- */
- end_column: number;
- };
+ /**
+ * Where does this block syntatically starts and ends (line number and
+ * column).
+ */
+ range: TextRange;
/** Sub-blocks of the current syntax block (e.g. methods of a class) */
children: SyntaxBlock[];
}
@@ -209,6 +209,25 @@
line_wrapping?: boolean;
}
+/**
+ * Event details when a token is highlighted.
+ */
+export declare interface TokenHighlightEventDetails {
+ token: string;
+ element: Element;
+ side: Side;
+ range: TextRange;
+}
+
+/**
+ * Listens to changes in token highlighting - when a new token starts or stopped
+ * being highlighted. undefined is sent if the event is about a clear in
+ * highlighting.
+ */
+export type TokenHighlightListener = (
+ tokenHighlightEvent?: TokenHighlightEventDetails
+) => void;
+
export declare interface ImageDiffPreferences {
automatic_blink?: boolean;
}
@@ -374,6 +393,7 @@
* @param textElement The rendered text of one side of the diff.
* @param lineNumberElement The rendered line number of one side of the diff.
* @param line Describes the line that should be annotated.
+ * @param side Which side of the diff is being annotated.
*/
annotate(
textElement: HTMLElement,
diff --git a/polygerrit-ui/app/api/embed.ts b/polygerrit-ui/app/api/embed.ts
index b1b7f34..520aeec 100644
--- a/polygerrit-ui/app/api/embed.ts
+++ b/polygerrit-ui/app/api/embed.ts
@@ -20,14 +20,24 @@
* limitations under the License.
*/
-import {DiffLayer, GrAnnotation, GrDiffCursor} from './diff';
+import {
+ DiffLayer,
+ GrAnnotation,
+ GrDiffCursor,
+ TokenHighlightListener,
+} from './diff';
declare global {
interface Window {
grdiff: {
GrAnnotation: GrAnnotation;
GrDiffCursor: {new (): GrDiffCursor};
- TokenHighlightLayer: {new (): DiffLayer};
+ TokenHighlightLayer: {
+ new (
+ container?: HTMLElement,
+ listener?: TokenHighlightListener
+ ): DiffLayer;
+ };
};
}
}
diff --git a/polygerrit-ui/app/api/gerrit.ts b/polygerrit-ui/app/api/gerrit.ts
index 8488961..2091eea 100644
--- a/polygerrit-ui/app/api/gerrit.ts
+++ b/polygerrit-ui/app/api/gerrit.ts
@@ -25,7 +25,7 @@
}
}
-export interface Gerrit {
+export declare interface Gerrit {
install(
callback: (plugin: PluginApi) => void,
opt_version?: string,
diff --git a/polygerrit-ui/app/api/hook.ts b/polygerrit-ui/app/api/hook.ts
index f8a6cc1..8cbb9d0 100644
--- a/polygerrit-ui/app/api/hook.ts
+++ b/polygerrit-ui/app/api/hook.ts
@@ -16,7 +16,7 @@
*/
import {ChangeInfo, ConfigInfo, RevisionInfo} from './rest-api';
-export interface GerritElementExtensions {
+export declare interface GerritElementExtensions {
content?: HTMLElement & {hidden?: boolean};
change?: ChangeInfo;
revision?: RevisionInfo;
diff --git a/polygerrit-ui/app/api/package.json b/polygerrit-ui/app/api/package.json
new file mode 100644
index 0000000..8af6832
--- /dev/null
+++ b/polygerrit-ui/app/api/package.json
@@ -0,0 +1,9 @@
+{
+ "name": "@gerritcodereview/typescript-api",
+ "version": "3.4.4",
+ "description": "Gerrit Code Review - TypeScript API",
+ "homepage": "https://www.gerritcodereview.com/",
+ "browser": true,
+ "dependencies": {},
+ "license": "Apache-2.0"
+}
diff --git a/polygerrit-ui/app/api/popup.ts b/polygerrit-ui/app/api/popup.ts
index 8d81831..d265ee6 100644
--- a/polygerrit-ui/app/api/popup.ts
+++ b/polygerrit-ui/app/api/popup.ts
@@ -17,9 +17,10 @@
export declare 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.
+ * Opens the popup, inserts it into the DOM over current UI.
+ * Creates the popup if not previously created. Creates and inserts the popup
+ * content element, if a `moduleName` was provided in the constructor.
+ * Otherwise you have to call `appendContent()` when the promise resolves.
*/
open(): Promise<PopupPluginApi>;
@@ -27,4 +28,10 @@
* Hides the popup.
*/
close(): void;
+
+ /**
+ * Appends the given element as a child to the popup. Only call this method
+ * when you have called `popup()` without a `moduleName`.
+ */
+ appendContent(el: HTMLElement): void;
}
diff --git a/polygerrit-ui/app/api/publish.sh b/polygerrit-ui/app/api/publish.sh
new file mode 100755
index 0000000..16de4c9
--- /dev/null
+++ b/polygerrit-ui/app/api/publish.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+# Should be executed from the root of the Gerrit repo:
+# polygerrit-ui/app/api/publish.sh
+#
+# Builds the npm package @gerritcodereview/typescript-api
+#
+# Adding the `--upload` argument will also publish the package.
+
+bazel_bin=$(which bazelisk 2>/dev/null)
+if [[ -z "$bazel_bin" ]]; then
+ echo "Warning: bazelisk is not installed; falling back to bazel."
+ bazel_bin=bazel
+fi
+api_path=polygerrit-ui/app/api
+
+function cleanup() {
+ echo "Cleaning up ..."
+ rm -f ${api_path}/BUILD
+}
+trap cleanup EXIT
+cp ${api_path}/BUILD_for_publishing_api_only ${api_path}/BUILD
+
+${bazel_bin} build //${api_path}:js_plugin_api_npm_package
+
+if [ "$1" == "--upload" ]; then
+ echo 'Uploading npm package @gerritcodereview/typescript-api'
+ ${bazel_bin} run //${api_path}:js_plugin_api_npm_package.publish
+fi
diff --git a/polygerrit-ui/app/api/rest-api.ts b/polygerrit-ui/app/api/rest-api.ts
index f3bb39b..f86e825 100644
--- a/polygerrit-ui/app/api/rest-api.ts
+++ b/polygerrit-ui/app/api/rest-api.ts
@@ -30,10 +30,6 @@
* enums =======================================================================
*/
-export enum AccountTag {
- SERVICE_USER = 'SERVICE_USER',
-}
-
/**
* The authentication type that is configured on the server.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#auth-info
@@ -237,7 +233,15 @@
_more_accounts?: boolean; // not set if false
status?: string; // status message of the account
inactive?: boolean; // not set if false
- tags?: AccountTag[];
+ tags?: string[];
+}
+
+/**
+ * The AccountDetailInfo entity contains detailed information about an account.
+ * https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#account-detail-info
+ */
+export declare interface AccountDetailInfo extends AccountInfo {
+ registered_on: Timestamp;
}
/**
@@ -245,7 +249,7 @@
* from the accounts section.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#accounts-config-info
*/
-export interface AccountsConfigInfo {
+export declare interface AccountsConfigInfo {
visibility: string;
default_display_name: DefaultDisplayNameConfig;
}
@@ -316,7 +320,7 @@
* configuration of the Gerrit server.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#auth-info
*/
-export interface AuthInfo {
+export declare interface AuthInfo {
auth_type: AuthType; // docs incorrectly names it 'type'
use_contributor_agreements?: boolean;
contributor_agreements?: ContributorAgreementInfo[];
@@ -352,7 +356,7 @@
* from the change section.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#change-config-info
*/
-export interface ChangeConfigInfo {
+export declare interface ChangeConfigInfo {
allow_blame?: boolean;
large_change: number;
update_delay: number;
@@ -460,14 +464,14 @@
* The CommentLinkInfo entity describes acommentlink.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#commentlink-info
*/
-export interface CommentLinkInfo {
+export declare interface CommentLinkInfo {
match: string;
link?: string;
enabled?: boolean;
html?: string;
}
-export interface CommentLinks {
+export declare interface CommentLinks {
[name: string]: CommentLinkInfo;
}
@@ -488,7 +492,8 @@
resolve_conflicts_web_links?: WebLinkInfo[];
}
-export interface ConfigArrayParameterInfo extends ConfigParameterInfoBase {
+export declare interface ConfigArrayParameterInfo
+ extends ConfigParameterInfoBase {
type: ConfigParameterInfoType.ARRAY;
values: string[];
}
@@ -498,7 +503,7 @@
* project configuration.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
*/
-export interface ConfigInfo {
+export declare interface ConfigInfo {
description?: string;
use_contributor_agreements?: InheritedBooleanInfo;
use_content_merge?: InheritedBooleanInfo;
@@ -521,7 +526,8 @@
reject_empty_commit?: InheritedBooleanInfo;
}
-export interface ConfigListParameterInfo extends ConfigParameterInfoBase {
+export declare interface ConfigListParameterInfo
+ extends ConfigParameterInfoBase {
type: ConfigParameterInfoType.LIST;
permitted_values?: string[];
}
@@ -535,7 +541,7 @@
* The ConfigParameterInfo entity describes a project configurationparameter.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-parameter-info
*/
-export interface ConfigParameterInfoBase {
+export declare interface ConfigParameterInfoBase {
display_name?: string;
description?: string;
warning?: string;
@@ -550,7 +556,7 @@
}
// https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#contributor-agreement-info
-export interface ContributorAgreementInfo {
+export declare interface ContributorAgreementInfo {
name: string;
description: string;
url: string;
@@ -580,7 +586,7 @@
* options.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#download-info
*/
-export interface DownloadInfo {
+export declare interface DownloadInfo {
schemes: SchemesInfoMap;
archives: string[];
}
@@ -590,7 +596,7 @@
* scheme and its commands.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html
*/
-export interface DownloadSchemeInfo {
+export declare interface DownloadSchemeInfo {
url: string;
is_auth_required: boolean;
is_auth_supported: boolean;
@@ -630,7 +636,7 @@
* the gerrit section.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#gerrit-info
*/
-export interface GerritInfo {
+export declare interface GerritInfo {
all_projects: string; // Doc contains incorrect name
all_users: string; // Doc contains incorrect name
doc_search: boolean;
@@ -681,7 +687,7 @@
* Gerrit internal group, or an external group that is known to Gerrit.
* https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html#group-info
*/
-export interface GroupInfo {
+export declare interface GroupInfo {
id: GroupId;
name?: GroupName;
url?: string;
@@ -702,7 +708,7 @@
* Options of the group.
* https://gerrit-review.googlesource.com/Documentation/rest-api-groups.html
*/
-export interface GroupOptionsInfo {
+export declare interface GroupOptionsInfo {
visible_to_all: boolean;
}
@@ -714,7 +720,7 @@
* A boolean value that can also be inherited.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#inherited-boolean-info
*/
-export interface InheritedBooleanInfo {
+export declare interface InheritedBooleanInfo {
value: boolean;
configured_value: InheritedBooleanInfoConfiguredValue;
inherited_value?: boolean;
@@ -746,7 +752,7 @@
* has.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#label-type-info
*/
-export interface LabelTypeInfo {
+export declare interface LabelTypeInfo {
values: LabelTypeInfoValues;
default_value: number;
}
@@ -761,7 +767,7 @@
* size limit of a project.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#max-object-size-limit-info
*/
-export interface MaxObjectSizeLimitInfo {
+export declare interface MaxObjectSizeLimitInfo {
value?: string;
configured_value?: string;
summary?: string;
@@ -789,7 +795,7 @@
* plugins.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#plugin-config-info
*/
-export interface PluginConfigInfo {
+export declare interface PluginConfigInfo {
has_avatars: boolean;
// Exists in Java class, but not mentioned in docs.
js_resource_paths: string[];
@@ -824,7 +830,7 @@
* The ProjectInfo entity contains information about a project
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#project-info
*/
-export interface ProjectInfo {
+export declare interface ProjectInfo {
id: UrlEncodedRepoName;
// name is not set if returned in a map where the project name is used as
// map key
@@ -841,7 +847,7 @@
web_links?: WebLinkInfo[];
}
-export interface ProjectInfoWithName extends ProjectInfo {
+export declare interface ProjectInfoWithName extends ProjectInfo {
name: RepoName;
}
@@ -887,7 +893,7 @@
* git-receive-pack behavior on the server.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#receive-info
*/
-export interface ReceiveInfo {
+export declare interface ReceiveInfo {
enable_signed_push?: string;
}
@@ -960,7 +966,7 @@
* Gerrit server.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#server-info
*/
-export interface ServerInfo {
+export declare interface ServerInfo {
accounts: AccountsConfigInfo;
auth: AuthInfo;
change: ChangeConfigInfo;
@@ -995,7 +1001,7 @@
* project inheritance.
* https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#submit-type-info
*/
-export interface SubmitTypeInfo {
+export declare interface SubmitTypeInfo {
value: Exclude<SubmitType, SubmitType.INHERIT>;
configured_value: SubmitType;
inherited_value: Exclude<SubmitType, SubmitType.INHERIT>;
@@ -1006,7 +1012,7 @@
* the suggest section.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#suggest-info
*/
-export interface SuggestInfo {
+export declare interface SuggestInfo {
from: number;
}
@@ -1034,7 +1040,7 @@
* from the user section.
* https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#user-config-info
*/
-export interface UserConfigInfo {
+export declare interface UserConfigInfo {
anonymous_coward_name: string;
}
diff --git a/polygerrit-ui/app/api/rest.ts b/polygerrit-ui/app/api/rest.ts
index 46dad3d..86f33a9 100644
--- a/polygerrit-ui/app/api/rest.ts
+++ b/polygerrit-ui/app/api/rest.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {ProjectInfoWithName, ServerInfo} from './rest-api';
+import {AccountDetailInfo, ProjectInfoWithName, ServerInfo} from './rest-api';
export type RequestPayload = string | object;
@@ -37,6 +37,8 @@
invalidateReposCache(): void;
+ getAccount(): Promise<AccountDetailInfo | undefined>;
+
getRepos(
filter: string,
reposPerPage: number,
diff --git a/polygerrit-ui/app/api/styles.ts b/polygerrit-ui/app/api/styles.ts
index e393667..55ac2cc 100644
--- a/polygerrit-ui/app/api/styles.ts
+++ b/polygerrit-ui/app/api/styles.ts
@@ -29,13 +29,15 @@
*/
/** Lit plugins can cast Style to CSSResult. */
-export interface Style {
+export declare interface Style {
toString(): string;
}
-export interface Styles {
+export declare interface Styles {
+ font: Style;
form: Style;
menuPage: Style;
+ spinner: Style;
subPage: Style;
table: Style;
}
diff --git a/polygerrit-ui/app/api/tsconfig.json b/polygerrit-ui/app/api/tsconfig.json
new file mode 100644
index 0000000..4d8ecac
--- /dev/null
+++ b/polygerrit-ui/app/api/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../../plugins/tsconfig-plugins-base.json",
+ "include": [
+ "**/*",
+ ],
+}
diff --git a/polygerrit-ui/app/compile_generated_templates.sh b/polygerrit-ui/app/compile_generated_templates.sh
new file mode 100755
index 0000000..68bf485
--- /dev/null
+++ b/polygerrit-ui/app/compile_generated_templates.sh
@@ -0,0 +1 @@
+$1 --project $2 --baseUrl ./external/ui_npm/node_modules/ --rootDir null
diff --git a/polygerrit-ui/app/constants/constants.ts b/polygerrit-ui/app/constants/constants.ts
index 84f1c15..645e770 100644
--- a/polygerrit-ui/app/constants/constants.ts
+++ b/polygerrit-ui/app/constants/constants.ts
@@ -22,7 +22,6 @@
import {DiffPreferencesInfo} from '../types/diff';
import {EditPreferencesInfo, PreferencesInfo} from '../types/common';
import {
- AccountTag,
AuthType,
ChangeStatus,
ConfigParameterInfoType,
@@ -42,7 +41,6 @@
} from '../api/rest-api';
export {
- AccountTag,
AuthType,
ChangeStatus,
ConfigParameterInfoType,
@@ -61,6 +59,10 @@
SubmitType,
};
+export enum AccountTag {
+ SERVICE_USER = 'SERVICE_USER',
+}
+
export enum PrimaryTab {
FILES = 'files',
/**
@@ -302,3 +304,7 @@
theme: 'DEFAULT',
};
}
+
+export const RELOAD_DASHBOARD_INTERVAL_MS = 10 * 1000;
+
+export const SHOWN_ITEMS_COUNT = 25;
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
index a09c1c3..a10bdda 100644
--- a/polygerrit-ui/app/constants/reporting.ts
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -23,6 +23,7 @@
VISIBILILITY_VISIBLE = 'Visibility changed to visible',
EXTENSION_DETECTED = 'Extension detected',
PLUGINS_INSTALLED = 'Plugins installed',
+ PLUGINS_FAILED = 'Some plugins failed to load',
USER_REFERRED_FROM = 'User referred from',
}
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
index c41fe57..2328a05 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-input/iron-input';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
@@ -114,7 +115,7 @@
_updateSection(section: PermissionAccessSection) {
this._permissions = toSortedPermissionsArray(section.value.permissions);
- this._originalId = section.id as GitRef;
+ this._originalId = section.id;
}
_handleAccessSaved() {
@@ -169,7 +170,9 @@
_computePermissions(
name: string,
capabilities?: CapabilityInfoMap,
- labels?: LabelNameToLabelTypeInfoMap
+ labels?: LabelNameToLabelTypeInfoMap,
+ // This is just for triggering re-computation. We don't use the value.
+ _?: unknown
) {
let allPermissions;
const section = this.section;
@@ -226,10 +229,10 @@
_computePermissionName(
name: string,
permission: PermissionArrayItem<EditablePermissionInfo>,
- capabilities: CapabilityInfoMap
- ) {
+ capabilities?: CapabilityInfoMap
+ ): string | undefined {
if (name === GLOBAL_NAME) {
- return capabilities[permission.id].name;
+ return capabilities?.[permission.id].name;
} else if (AccessPermissions[permission.id]) {
return AccessPermissions[permission.id].name;
} else if (permission.value.label) {
@@ -312,7 +315,7 @@
if (
editing &&
this.section &&
- this._isEditEnabled(canUpload, ownerOf, this.section.id as GitRef)
+ this._isEditEnabled(canUpload, ownerOf, this.section.id)
) {
classList.push('editing');
}
@@ -330,7 +333,7 @@
}
_handleAddPermission() {
- const value = this.$.permissionSelect.value;
+ const value = this.$.permissionSelect.value as GitRef;
const permission: PermissionArrayItem<EditablePermissionInfo> = {
id: value,
value: {rules: {}, added: true},
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
index 46968eb..1438825 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
index 3e52165..b438420 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
@@ -23,7 +23,6 @@
import '../gr-create-group-dialog/gr-create-group-dialog';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-admin-group-list_html';
-import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property, observe, computed} from '@polymer/decorators';
import {AppElementAdminParams} from '../../gr-app-types';
@@ -32,6 +31,7 @@
import {GrCreateGroupDialog} from '../gr-create-group-dialog/gr-create-group-dialog';
import {fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {SHOWN_ITEMS_COUNT} from '../../../constants/constants';
declare global {
interface HTMLElementTagNameMap {
@@ -47,7 +47,7 @@
}
@customElement('gr-admin-group-list')
-export class GrAdminGroupList extends ListViewMixin(PolymerElement) {
+export class GrAdminGroupList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -79,7 +79,7 @@
* */
@computed('_groups')
get _shownGroups() {
- return this.computeShownItems(this._groups);
+ return this._groups.slice(0, SHOWN_ITEMS_COUNT);
}
@property({type: Number})
@@ -103,8 +103,8 @@
@observe('params')
_paramsChanged(params: AppElementAdminParams) {
this._loading = true;
- this._filter = this.getFilterValue(params);
- this._offset = this.getOffsetValue(params);
+ this._filter = params?.filter ?? '';
+ this._offset = Number(params?.offset ?? 0);
return this._getGroups(this._filter, this._groupsPerPage, this._offset);
}
@@ -181,4 +181,8 @@
_visibleToAll(item: GroupInfo) {
return item.options?.visible_to_all === true ? 'Y' : 'N';
}
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
}
diff --git a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
index a2d62341..04d3198 100644
--- a/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-confirm-delete-item-dialog/gr-confirm-delete-item-dialog.ts
@@ -16,8 +16,8 @@
*/
import '../../shared/gr-dialog/gr-dialog';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {css, html, LitElement} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -26,7 +26,7 @@
}
@customElement('gr-confirm-delete-item-dialog')
-export class GrConfirmDeleteItemDialog extends GrLitElement {
+export class GrConfirmDeleteItemDialog extends LitElement {
/**
* Fired when the confirm button is pressed.
*
@@ -45,7 +45,7 @@
@property({type: String})
itemTypeName?: string;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -57,7 +57,7 @@
];
}
- render() {
+ override render() {
const item = this.item ?? 'UNKNOWN ITEM';
const itemTypeName = this.itemTypeName ?? 'UNKNOWN ITEM TYPE';
return html` <gr-dialog
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
index 63b10ec..15f6f4b 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
@@ -32,7 +32,7 @@
InheritedBooleanInfo,
} from '../../../types/common';
import {InheritedBooleanInfoConfiguredValue} from '../../../constants/constants';
-import {GrAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {GrTypedAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete';
import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
import {appContext} from '../../../services/app-context';
import {Subject} from 'rxjs';
@@ -41,6 +41,7 @@
serverConfig$,
} from '../../../services/config/config-model';
import {takeUntil} from 'rxjs/operators';
+import {IronInputElement} from '@polymer/iron-input/iron-input';
const SUGGESTIONS_LIMIT = 15;
const REF_PREFIX = 'refs/heads/';
@@ -48,8 +49,8 @@
export interface GrCreateChangeDialog {
$: {
privateChangeCheckBox: HTMLInputElement;
- branchInput: GrAutocomplete;
- tagNameInput: HTMLInputElement;
+ branchInput: GrTypedAutocomplete<BranchName>;
+ tagNameInput: IronInputElement;
messageInput: IronAutogrowTextareaElement;
};
}
@@ -63,19 +64,19 @@
repoName?: RepoName;
@property({type: String})
- branch?: BranchName;
+ branch = '' as BranchName;
@property({type: Object})
_repoConfig?: ConfigInfo;
@property({type: String})
- subject?: string;
+ subject = '';
@property({type: String})
topic?: string;
@property({type: Object})
- _query?: (input: string) => Promise<{name: string}[]>;
+ _query?: (input: string) => Promise<{name: BranchName}[]>;
@property({type: String})
baseChange?: ChangeId;
@@ -90,7 +91,7 @@
canCreate = false;
@property({type: Boolean})
- _privateChangesEnabled?: boolean;
+ _privateChangesEnabled = false;
restApiService = appContext.restApiService;
@@ -120,7 +121,7 @@
super.disconnectedCallback();
}
- _computeBranchClass(baseChange: boolean) {
+ _computeBranchClass(baseChange?: ChangeId) {
return baseChange ? 'hide' : '';
}
@@ -165,19 +166,19 @@
.getRepoBranches(input, this.repoName, SUGGESTIONS_LIMIT)
.then(response => {
if (!response) return [];
- const branches = [];
+ const branches: Array<{name: BranchName}> = [];
for (const branchInfo of response) {
let name: string = branchInfo.ref;
if (name.startsWith('refs/heads/')) {
name = name.substring('refs/heads/'.length);
}
- branches.push({name});
+ branches.push({name: name as BranchName});
}
return branches;
});
}
- _formatBooleanString(config: InheritedBooleanInfo) {
+ _formatBooleanString(config?: InheritedBooleanInfo) {
if (
config &&
config.configured_value === InheritedBooleanInfoConfiguredValue.TRUE
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
index a9de24a..9ed5d81 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
@@ -20,7 +20,11 @@
import {GrCreateChangeDialog} from './gr-create-change-dialog';
import {BranchName, GitRef, RepoName} from '../../../types/common';
import {InheritedBooleanInfoConfiguredValue} from '../../../constants/constants';
-import {createChange, createConfig} from '../../../test/test-data-generators';
+import {
+ createChange,
+ createConfig,
+ TEST_CHANGE_ID,
+} from '../../../test/test-data-generators';
import {stubRestApi} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-create-change-dialog');
@@ -130,8 +134,8 @@
});
test('_computeBranchClass', () => {
- assert.equal(element._computeBranchClass(true), 'hide');
- assert.equal(element._computeBranchClass(false), '');
+ assert.equal(element._computeBranchClass(TEST_CHANGE_ID), 'hide');
+ assert.equal(element._computeBranchClass(undefined), '');
});
test('_computePrivateSectionClass', () => {
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
index af33691..321f069 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
@@ -31,41 +31,33 @@
element = basicFixture.instantiate();
});
- test('name is updated correctly', done => {
+ test('name is updated correctly', async () => {
assert.isFalse(element.hasNewGroupName);
const inputEl = element.root.querySelector('iron-input');
inputEl.bindValue = GROUP_NAME;
- setTimeout(() => {
- assert.isTrue(element.hasNewGroupName);
- assert.deepEqual(element._name, GROUP_NAME);
- done();
- });
+ await new Promise(resolve => setTimeout(resolve));
+ assert.isTrue(element.hasNewGroupName);
+ assert.deepEqual(element._name, GROUP_NAME);
});
- test('test for redirecting to group on successful creation', done => {
+ test('test for redirecting to group on successful creation', async () => {
stubRestApi('createGroup').returns(Promise.resolve({status: 201}));
stubRestApi('getGroupConfig').returns(Promise.resolve({group_id: 551}));
const showStub = sinon.stub(page, 'show');
- element.handleCreateGroup()
- .then(() => {
- assert.isTrue(showStub.calledWith('/admin/groups/551'));
- done();
- });
+ await element.handleCreateGroup();
+ assert.isTrue(showStub.calledWith('/admin/groups/551'));
});
- test('test for unsuccessful group creation', done => {
+ test('test for unsuccessful group creation', async () => {
stubRestApi('createGroup').returns(Promise.resolve({status: 409}));
stubRestApi('getGroupConfig').returns(Promise.resolve({group_id: 551}));
const showStub = sinon.stub(page, 'show');
- element.handleCreateGroup()
- .then(() => {
- assert.isFalse(showStub.called);
- done();
- });
+ await element.handleCreateGroup();
+ assert.isFalse(showStub.called);
});
});
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
index b6a08b87..ea0919c 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.ts
@@ -35,7 +35,7 @@
element = basicFixture.instantiate();
});
- test('branch created', done => {
+ test('branch created', async () => {
stubRestApi('createRepoBranch').returns(Promise.resolve(new Response()));
assert.isFalse(element.hasNewItemName);
@@ -46,15 +46,14 @@
ironInput(element.$.itemNameSection).bindValue = 'test-branch2';
ironInput(element.$.itemRevisionSection).bindValue = 'HEAD';
- setTimeout(() => {
- assert.isTrue(element.hasNewItemName);
- assert.equal(element._itemName, 'test-branch2' as BranchName);
- assert.equal(element._itemRevision, 'HEAD');
- done();
- });
+ await flush();
+
+ assert.isTrue(element.hasNewItemName);
+ assert.equal(element._itemName, 'test-branch2' as BranchName);
+ assert.equal(element._itemRevision, 'HEAD');
});
- test('tag created', done => {
+ test('tag created', async () => {
stubRestApi('createRepoTag').returns(Promise.resolve(new Response()));
assert.isFalse(element.hasNewItemName);
@@ -65,15 +64,13 @@
ironInput(element.$.itemNameSection).bindValue = 'test-tag2';
ironInput(element.$.itemRevisionSection).bindValue = 'HEAD';
- setTimeout(() => {
- assert.isTrue(element.hasNewItemName);
- assert.equal(element._itemName, 'test-tag2' as BranchName);
- assert.equal(element._itemRevision, 'HEAD');
- done();
- });
+ await flush();
+ assert.isTrue(element.hasNewItemName);
+ assert.equal(element._itemName, 'test-tag2' as BranchName);
+ assert.equal(element._itemRevision, 'HEAD');
});
- test('tag created with annotations', done => {
+ test('tag created with annotations', async () => {
stubRestApi('createRepoTag').returns(Promise.resolve(new Response()));
assert.isFalse(element.hasNewItemName);
@@ -86,13 +83,11 @@
ironInput(element.$.itemAnnotationSection).bindValue = 'test-message2';
ironInput(element.$.itemRevisionSection).bindValue = 'HEAD';
- setTimeout(() => {
- assert.isTrue(element.hasNewItemName);
- assert.equal(element._itemName, 'test-tag2' as BranchName);
- assert.equal(element._itemAnnotation, 'test-message2');
- assert.equal(element._itemRevision, 'HEAD');
- done();
- });
+ await flush();
+ assert.isTrue(element.hasNewItemName);
+ assert.equal(element._itemName, 'test-tag2' as BranchName);
+ assert.equal(element._itemAnnotation, 'test-message2');
+ assert.equal(element._itemRevision, 'HEAD');
});
test('_computeHideItemClass returns hideItem if type is branches', () => {
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 cdc2fb3..6605350 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
@@ -17,11 +17,9 @@
import '../../../styles/gr-table-styles';
import '../../../styles/shared-styles';
-import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../shared/gr-account-link/gr-account-link';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-group-audit-log_html';
-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 {
@@ -37,7 +35,7 @@
import {ErrorCallback} from '../../../api/rest';
@customElement('gr-group-audit-log')
-export class GrGroupAuditLog extends ListViewMixin(PolymerElement) {
+export class GrGroupAuditLog extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -127,6 +125,10 @@
return '';
}
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
index 40c2f30..828aa55 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
@@ -43,7 +43,7 @@
<template is="dom-repeat" items="[[_auditLog]]">
<tr class="table">
<td class="date">
- <gr-date-formatter has-tooltip="" date-str="[[item.date]]">
+ <gr-date-formatter withTooltip date-str="[[item.date]]">
</gr-date-formatter>
</td>
<td class="type">[[itemType(item.type)]]</td>
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 70242d8..c38f8be 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
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/gr-table-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
index 0c856bc..518abac 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-form-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
index 54c5099..b91b04b 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
@@ -18,7 +18,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-group-members.js';
import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {addListenerForTest, stubBaseUrl, stubRestApi} from '../../../test/test-utils.js';
+import {addListenerForTest, mockPromise, stubBaseUrl, stubRestApi} from '../../../test/test-utils.js';
import {ItemType} from './gr-group-members.js';
const basicFixture = fixtureFromElement('gr-group-members');
@@ -140,7 +140,7 @@
'https://test/site/group/url');
});
- test('save members correctly', () => {
+ test('save members correctly', async () => {
element._groupOwner = true;
const memberName = 'test-admin';
@@ -155,6 +155,7 @@
element.$.groupMemberSearchInput.text = memberName;
element.$.groupMemberSearchInput.value = 1234;
+ await flush();
assert.isFalse(button.hasAttribute('disabled'));
return element._handleSavingGroupMember().then(() => {
@@ -165,7 +166,7 @@
});
});
- test('save included groups correctly', () => {
+ test('save included groups correctly', async () => {
element._groupOwner = true;
const includedGroupName = 'testName';
@@ -179,7 +180,7 @@
element.$.includedGroupSearchInput.text = includedGroupName;
element.$.includedGroupSearchInput.value = 'testId';
-
+ await flush();
assert.isFalse(button.hasAttribute('disabled'));
return element._handleSavingIncludedGroups().then(() => {
@@ -235,42 +236,32 @@
assert.isTrue(exceptionThrown);
});
- test('_getAccountSuggestions empty', done => {
- element
- ._getAccountSuggestions('nonexistent').then(accounts => {
- assert.equal(accounts.length, 0);
- done();
- });
+ test('_getAccountSuggestions empty', async () => {
+ const accounts = await element._getAccountSuggestions('nonexistent');
+ assert.equal(accounts.length, 0);
});
- test('_getAccountSuggestions non-empty', done => {
- element
- ._getAccountSuggestions('test-').then(accounts => {
- assert.equal(accounts.length, 3);
- assert.equal(accounts[0].name,
- 'test-account <test.account@example.com>');
- assert.equal(accounts[1].name, 'test-admin <test.admin@example.com>');
- assert.equal(accounts[2].name, 'test-git');
- done();
- });
+ test('_getAccountSuggestions non-empty', async () => {
+ const accounts = await element._getAccountSuggestions('test-');
+ assert.equal(accounts.length, 3);
+ assert.equal(accounts[0].name,
+ 'test-account <test.account@example.com>');
+ assert.equal(accounts[1].name, 'test-admin <test.admin@example.com>');
+ assert.equal(accounts[2].name, 'test-git');
});
- test('_getGroupSuggestions empty', done => {
- element
- ._getGroupSuggestions('nonexistent').then(groups => {
- assert.equal(groups.length, 0);
- done();
- });
+ test('_getGroupSuggestions empty', async () => {
+ const groups = await element._getGroupSuggestions('nonexistent');
+
+ assert.equal(groups.length, 0);
});
- test('_getGroupSuggestions non-empty', done => {
- element
- ._getGroupSuggestions('test').then(groups => {
- assert.equal(groups.length, 2);
- assert.equal(groups[0].name, 'test-admin');
- assert.equal(groups[1].name, 'test/Administrator (admin)');
- done();
- });
+ test('_getGroupSuggestions non-empty', async () => {
+ const groups = await element._getGroupSuggestions('test');
+
+ assert.equal(groups.length, 2);
+ assert.equal(groups[0].name, 'test-admin');
+ assert.equal(groups[1].name, 'test/Administrator (admin)');
});
test('_computeHideItemClass returns string for admin', () => {
@@ -343,22 +334,24 @@
assert.equal(element._computeGroupUrl(url), url);
});
- test('fires page-error', done => {
+ test('fires page-error', async () => {
groupStub.restore();
element.groupId = 1;
const response = {status: 404};
- stubRestApi('getGroupConfig')
- .callsFake((group, errFn) => {
- errFn(response);
- });
+ stubRestApi('getGroupConfig').callsFake((group, errFn) => {
+ errFn(response);
+ return Promise.resolve();
+ });
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
element._loadGroupDetails();
+ await promise;
});
test('_computeItemName', () => {
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 18862b5..596fe5b 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
index 98d21f9..6bc5d2a 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
index 0668330..e390ac5 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
@@ -17,7 +17,11 @@
import '../../../test/common-test-setup-karma.js';
import './gr-group.js';
-import {stubRestApi, addListenerForTest} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi,
+} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-group');
@@ -49,17 +53,15 @@
.display === 'none');
});
- test('default values are populated with internal group', done => {
+ test('default values are populated with internal group', async () => {
stubRestApi('getIsGroupOwner').returns(Promise.resolve(true));
element.groupId = 1;
- element._loadGroup().then(() => {
- assert.isTrue(element._groupIsInternal);
- assert.isFalse(element.$.visibleToAll.bindValue);
- done();
- });
+ await element._loadGroup();
+ assert.isTrue(element._groupIsInternal);
+ assert.isFalse(element.$.visibleToAll.bindValue);
});
- test('default values with external group', done => {
+ test('default values with external group', async () => {
const groupExternal = {...group};
groupExternal.id = 'external-group-id';
groupStub.restore();
@@ -67,14 +69,12 @@
Promise.resolve(groupExternal));
stubRestApi('getIsGroupOwner').returns(Promise.resolve(true));
element.groupId = 1;
- element._loadGroup().then(() => {
- assert.isFalse(element._groupIsInternal);
- assert.isFalse(element.$.visibleToAll.bindValue);
- done();
- });
+ await element._loadGroup();
+ assert.isFalse(element._groupIsInternal);
+ assert.isFalse(element.$.visibleToAll.bindValue);
});
- test('rename group', done => {
+ test('rename group', async () => {
const groupName = 'test-group';
const groupName2 = 'test-group2';
element.groupId = 1;
@@ -88,25 +88,23 @@
const button = element.$.inputUpdateNameBtn;
- element._loadGroup().then(() => {
- assert.isTrue(button.hasAttribute('disabled'));
- assert.isFalse(element.$.Title.classList.contains('edited'));
+ await element._loadGroup();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.isFalse(element.$.Title.classList.contains('edited'));
- element.$.groupNameInput.text = groupName2;
+ element.$.groupNameInput.text = groupName2;
- assert.isFalse(button.hasAttribute('disabled'));
- assert.isTrue(element.$.groupName.classList.contains('edited'));
+ await flush();
+ assert.isFalse(button.hasAttribute('disabled'));
+ assert.isTrue(element.$.groupName.classList.contains('edited'));
- element._handleSaveName().then(() => {
- assert.isTrue(button.hasAttribute('disabled'));
- assert.isFalse(element.$.Title.classList.contains('edited'));
- assert.equal(element._groupName, groupName2);
- done();
- });
- });
+ await element._handleSaveName();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.isFalse(element.$.Title.classList.contains('edited'));
+ assert.equal(element._groupName, groupName2);
});
- test('rename group owner', done => {
+ test('rename group owner', async () => {
const groupName = 'test-group';
element.groupId = 1;
element._groupConfig = {
@@ -119,24 +117,22 @@
const button = element.$.inputUpdateOwnerBtn;
- element._loadGroup().then(() => {
- assert.isTrue(button.hasAttribute('disabled'));
- assert.isFalse(element.$.Title.classList.contains('edited'));
+ await element._loadGroup();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.isFalse(element.$.Title.classList.contains('edited'));
- element.$.groupOwnerInput.text = 'testId2';
+ element.$.groupOwnerInput.text = 'testId2';
- assert.isFalse(button.hasAttribute('disabled'));
- assert.isTrue(element.$.groupOwner.classList.contains('edited'));
+ await flush();
+ assert.isFalse(button.hasAttribute('disabled'));
+ assert.isTrue(element.$.groupOwner.classList.contains('edited'));
- element._handleSaveOwner().then(() => {
- assert.isTrue(button.hasAttribute('disabled'));
- assert.isFalse(element.$.Title.classList.contains('edited'));
- done();
- });
- });
+ await element._handleSaveOwner();
+ assert.isTrue(button.hasAttribute('disabled'));
+ assert.isFalse(element.$.Title.classList.contains('edited'));
});
- test('test for undefined group name', done => {
+ test('test for undefined group name', async () => {
groupStub.restore();
stubRestApi('getGroupConfig').returns(Promise.resolve({}));
@@ -149,16 +145,13 @@
// Test that loading shows instead of filling
// in group details
- element._loadGroup().then(() => {
- assert.isTrue(element.$.loading.classList.contains('loading'));
+ await element._loadGroup();
+ assert.isTrue(element.$.loading.classList.contains('loading'));
- assert.isTrue(element._loading);
-
- done();
- });
+ assert.isTrue(element._loading);
});
- test('test fire event', done => {
+ test('test fire event', async () => {
element._groupConfig = {
name: 'test-group',
};
@@ -166,11 +159,8 @@
stubRestApi('saveGroupName').returns(Promise.resolve({status: 200}));
const showStub = sinon.stub(element, 'dispatchEvent');
- element._handleSaveName()
- .then(() => {
- assert.isTrue(showStub.called);
- done();
- });
+ await element._handleSaveName();
+ assert.isTrue(showStub.called);
});
test('_computeGroupDisabled', () => {
@@ -206,7 +196,7 @@
assert.equal(element._computeLoadingClass(false), '');
});
- test('fires page-error', done => {
+ test('fires page-error', async () => {
groupStub.restore();
element.groupId = 1;
@@ -214,14 +204,17 @@
const response = {status: 404};
stubRestApi('getGroupConfig').callsFake((group, errFn) => {
errFn(response);
+ return Promise.resolve(undefined);
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
element._loadGroup();
+ await promise;
});
test('uuid', () => {
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 f275dfd..9f51688 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
@@ -19,21 +19,21 @@
import '../../shared/gr-list-view/gr-list-view';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-plugin-list_html';
-import {
- ListViewMixin,
- ListViewParams,
-} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {customElement, property} from '@polymer/decorators';
import {PluginInfo} from '../../../types/common';
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
+import {encodeURL, getBaseUrl} from '../../../utils/url-util';
+import {SHOWN_ITEMS_COUNT} from '../../../constants/constants';
+import {ListViewParams} from '../../gr-app-types';
interface PluginInfoWithName extends PluginInfo {
name: string;
}
+
@customElement('gr-plugin-list')
-export class GrPluginList extends ListViewMixin(PolymerElement) {
+export class GrPluginList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -81,8 +81,8 @@
_paramsChanged(params: ListViewParams) {
this._loading = true;
- this._filter = this.getFilterValue(params);
- this._offset = this.getOffsetValue(params);
+ this._filter = params?.filter ?? '';
+ this._offset = Number(params?.offset ?? 0);
return this._getPlugins(this._filter, this._pluginsPerPage, this._offset);
}
@@ -110,7 +110,15 @@
}
_computePluginUrl(id: string) {
- return this.getUrl('/', id);
+ return getBaseUrl() + '/' + encodeURL(id, true);
+ }
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
+
+ computeShownItems(plugins: PluginInfoWithName[]) {
+ return plugins.slice(0, SHOWN_ITEMS_COUNT);
}
}
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
index a9281e4..62c89b2 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
@@ -18,7 +18,10 @@
import '../../../test/common-test-setup-karma.js';
import './gr-plugin-list.js';
import 'lodash/lodash.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-plugin-list');
@@ -52,52 +55,45 @@
counter = 0;
});
- suite('list with plugins', () => {
- setup(done => {
+ suite('list with plugins', async () => {
+ setup(async () => {
plugins = _.times(26, pluginGenerator);
stubRestApi('getPlugins').returns(Promise.resolve(plugins));
- element._paramsChanged(value).then(() => { flush(done); });
+ await element._paramsChanged(value);
+ await flush();
});
- test('plugin in the list is formatted correctly', done => {
- flush(() => {
- assert.equal(element._plugins[4].id, 'test5');
- assert.equal(element._plugins[4].index_url, 'plugins/test5/');
- assert.equal(element._plugins[4].version, 'version-5');
- assert.equal(element._plugins[4].api_version, 'api-version-5');
- assert.equal(element._plugins[4].disabled, false);
- done();
- });
+ test('plugin in the list is formatted correctly', async () => {
+ await flush();
+ assert.equal(element._plugins[4].id, 'test5');
+ assert.equal(element._plugins[4].index_url, 'plugins/test5/');
+ assert.equal(element._plugins[4].version, 'version-5');
+ assert.equal(element._plugins[4].api_version, 'api-version-5');
+ assert.equal(element._plugins[4].disabled, false);
});
- test('with and without urls', done => {
- flush(() => {
- const names = element.root.querySelectorAll('.name');
- assert.isOk(names[1].querySelector('a'));
- assert.equal(names[1].querySelector('a').innerText, 'test1');
- assert.isNotOk(names[2].querySelector('a'));
- assert.equal(names[2].innerText, 'test2');
- done();
- });
+ test('with and without urls', async () => {
+ await flush();
+ const names = element.root.querySelectorAll('.name');
+ assert.isOk(names[1].querySelector('a'));
+ assert.equal(names[1].querySelector('a').innerText, 'test1');
+ assert.isNotOk(names[2].querySelector('a'));
+ assert.equal(names[2].innerText, 'test2');
});
- test('versions', done => {
- flush(() => {
- const versions = element.root.querySelectorAll('.version');
- assert.equal(versions[2].innerText, 'version-2');
- assert.equal(versions[3].innerText, '--');
- done();
- });
+ test('versions', async () => {
+ await flush();
+ const versions = element.root.querySelectorAll('.version');
+ assert.equal(versions[2].innerText, 'version-2');
+ assert.equal(versions[3].innerText, '--');
});
- test('api versions', done => {
- flush(() => {
- const apiVersions = element.root.querySelectorAll(
- '.apiVersion');
- assert.equal(apiVersions[3].innerText, 'api-version-3');
- assert.equal(apiVersions[4].innerText, '--');
- done();
- });
+ test('api versions', async () => {
+ await flush();
+ const apiVersions = element.root.querySelectorAll(
+ '.apiVersion');
+ assert.equal(apiVersions[3].innerText, 'api-version-3');
+ assert.equal(apiVersions[4].innerText, '--');
});
test('_shownPlugins', () => {
@@ -106,10 +102,11 @@
});
suite('list with less then 26 plugins', () => {
- setup(done => {
+ setup(async () => {
plugins = _.times(25, pluginGenerator);
stubRestApi('getPlugins').returns(Promise.resolve(plugins));
- element._paramsChanged(value).then(() => { flush(done); });
+ await element._paramsChanged(value);
+ await flush();
});
test('_shownPlugins', () => {
@@ -133,7 +130,7 @@
});
suite('loading', () => {
- test('correct contents are displayed', () => {
+ test('correct contents are displayed', async () => {
assert.isTrue(element._loading);
assert.equal(element.computeLoadingClass(element._loading), 'loading');
assert.equal(getComputedStyle(element.$.loading).display, 'block');
@@ -141,30 +138,33 @@
element._loading = false;
element._plugins = _.times(25, pluginGenerator);
- flush();
+ await flush();
assert.equal(element.computeLoadingClass(element._loading), '');
assert.equal(getComputedStyle(element.$.loading).display, 'none');
});
});
suite('404', () => {
- test('fires page-error', done => {
+ test('fires page-error', async () => {
const response = {status: 404};
stubRestApi('getPlugins').callsFake(
(filter, pluginsPerPage, opt_offset, errFn) => {
errFn(response);
+ return Promise.resolve(undefined);
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
const value = {
filter: 'test',
offset: 25,
};
- element._paramsChanged(value);
+ await element._paramsChanged(value);
+ await promise;
});
});
});
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
index 08493c5..6136f1e1 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access-interfaces.ts
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/**
- * @fileOverview This file contains interfaces shared between gr-repo-access
+ * @fileoverview This file contains interfaces shared between gr-repo-access
* and nested elements (gr-access-section, gr-permission)
*/
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 9c98545..56e981a 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-menu-page-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
index f5ef86b..65f0564 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
index 2b7fdf5..1ccfd5e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
@@ -20,7 +20,11 @@
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import {toSortedPermissionsArray} from '../../../utils/access-util.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi,
+} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-repo-access');
@@ -238,19 +242,22 @@
assert.equal(element._computeLoadingClass(false), '');
});
- test('fires page-error', done => {
+ test('fires page-error', async () => {
const response = {status: 404};
stubRestApi('getRepoAccessRights').callsFake((repoName, errFn) => {
errFn(response);
+ return Promise.resolve(undefined);
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
element.repo = 'test';
+ await promise;
});
suite('with defined sections', () => {
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 3cef13f..de43dc6 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
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
index f572ac3..9948f8f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
@@ -36,11 +39,11 @@
<div id="loadedContent" class$="[[_computeLoadingClass(_loading)]]">
<h2 id="options" class="heading-2">Command</h2>
<div id="form">
- <h3>Create change</h3>
+ <h3 class="heading-3">Create change</h3>
<gr-button loading="[[_creatingChange]]" on-click="_createNewChange">
Create change
</gr-button>
- <h3>Edit repo config</h3>
+ <h3 class="heading-3">Edit repo config</h3>
<gr-button
id="editRepoConfig"
loading="[[_editingConfig]]"
@@ -48,7 +51,7 @@
>
Edit repo config
</gr-button>
- <h3 hidden="[[!_repoConfig.actions.gc.enabled]]">
+ <h3 class="heading-3" hidden="[[!_repoConfig.actions.gc.enabled]]">
[[_repoConfig.actions.gc.label]]
</h3>
<gr-button
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
index 893efe55..ac48484 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
@@ -18,7 +18,11 @@
import '../../../test/common-test-setup-karma.js';
import './gr-repo-commands.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi,
+} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-repo-commands');
@@ -112,7 +116,7 @@
});
suite('404', () => {
- test('fires page-error', done => {
+ test('fires page-error', async () => {
repoStub.restore();
element.repo = 'test';
@@ -120,13 +124,18 @@
const response = {status: 404};
stubRestApi('getProjectConfig').callsFake((repo, errFn) => {
errFn(response);
+ return Promise.resolve(undefined);
});
+
+ await flush();
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
element._loadRepo();
+ await promise;
});
});
});
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 4cc0a80..7800653 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
@@ -22,8 +22,8 @@
import {ErrorCallback} from '../../../api/rest';
import {sharedStyles} from '../../../styles/shared-styles';
import {tableStyles} from '../../../styles/gr-table-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, PropertyValues} from 'lit-element';
+import {LitElement, css, html, PropertyValues} from 'lit';
+import {customElement, property} from 'lit/decorators';
interface DashboardRef {
section: string;
@@ -31,7 +31,7 @@
}
@customElement('gr-repo-dashboards')
-export class GrRepoDashboards extends GrLitElement {
+export class GrRepoDashboards extends LitElement {
@property({type: String})
repo?: RepoName;
@@ -43,7 +43,7 @@
private readonly restApiService = appContext.restApiService;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
tableStyles,
@@ -63,7 +63,7 @@
];
}
- render() {
+ override render() {
return html` <table
id="list"
class="genericList ${this._computeLoadingClass(this._loading)}"
@@ -114,7 +114,7 @@
</table>`;
}
- updated(changedProperties: PropertyValues) {
+ override updated(changedProperties: PropertyValues) {
if (changedProperties.has('repo')) {
this.repoChanged();
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.ts
index ede2bb9..a54eafb 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.ts
@@ -21,6 +21,7 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {
addListenerForTest,
+ mockPromise,
queryAndAssert,
stubRestApi,
} from '../../../test/test-utils';
@@ -92,7 +93,7 @@
);
});
- test('loading, sections, and ordering', done => {
+ test('loading, sections, and ordering', async () => {
assert.isTrue(element._loading);
assert.notEqual(
getComputedStyle(queryAndAssert(element, '#loadingContainer')).display,
@@ -103,29 +104,25 @@
'none'
);
element.repo = 'test' as RepoName;
- flush(() => {
- assert.equal(
- getComputedStyle(queryAndAssert(element, '#loadingContainer'))
- .display,
- 'none'
- );
- assert.notEqual(
- getComputedStyle(queryAndAssert(element, '#dashboards')).display,
- 'none'
- );
+ await flush();
+ assert.equal(
+ getComputedStyle(queryAndAssert(element, '#loadingContainer')).display,
+ 'none'
+ );
+ assert.notEqual(
+ getComputedStyle(queryAndAssert(element, '#dashboards')).display,
+ 'none'
+ );
- const dashboard = element._dashboards!;
- assert.equal(dashboard.length!, 2);
- assert.equal(dashboard[0].section!, 'custom');
- assert.equal(dashboard[1].section!, 'default');
+ const dashboard = element._dashboards!;
+ assert.equal(dashboard.length!, 2);
+ assert.equal(dashboard[0].section!, 'custom');
+ assert.equal(dashboard[1].section!, 'default');
- const dashboards = dashboard[0].dashboards;
- assert.equal(dashboards.length, 2);
- assert.equal(dashboards[0].id, 'custom:custom1');
- assert.equal(dashboards[1].id, 'custom:custom2');
-
- done();
- });
+ const dashboards = dashboard[0].dashboards;
+ assert.equal(dashboards.length, 2);
+ assert.equal(dashboards[0].id, 'custom:custom1');
+ assert.equal(dashboards[1].id, 'custom:custom2');
});
});
@@ -148,19 +145,21 @@
});
suite('404', () => {
- test('fires page-error', done => {
+ test('fires page-error', async () => {
const response = {status: 404} as Response;
stubRestApi('getRepoDashboards').callsFake((_repo, errFn) => {
errFn!(response);
return Promise.resolve([]);
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual((e as PageErrorEvent).detail.response, response);
- done();
+ promise.resolve();
});
element.repo = 'test' as RepoName;
+ await promise;
});
});
});
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 e243974..00c5999 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
@@ -30,7 +30,6 @@
import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-detail-list_html';
-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 {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
@@ -49,6 +48,7 @@
import {firePageError} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {ErrorCallback} from '../../../api/rest';
+import {SHOWN_ITEMS_COUNT} from '../../../constants/constants';
const PGP_START = '-----BEGIN PGP SIGNATURE-----';
@@ -59,8 +59,9 @@
createNewModal: GrCreatePointerDialog;
};
}
+
@customElement('gr-repo-detail-list')
-export class GrRepoDetailList extends ListViewMixin(PolymerElement) {
+export class GrRepoDetailList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -151,8 +152,8 @@
this.detailType = params.detail;
- this._filter = this.getFilterValue(params);
- this._offset = this.getOffsetValue(params);
+ this._filter = params?.filter ?? '';
+ this._offset = Number(params?.offset ?? 0);
if (!this.detailType)
return Promise.reject(new Error('undefined detailType'));
@@ -391,6 +392,14 @@
_computeHideTagger(tagger?: GitPersonInfo) {
return tagger ? '' : 'hide';
}
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
+
+ computeShownItems(items: BranchInfo[] | TagInfo[]) {
+ return items.slice(0, SHOWN_ITEMS_COUNT);
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
index 4f66f0d..429a6d6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
@@ -145,10 +145,7 @@
<td class$="tagger [[_hideIfBranch(detailType)]]">
<div class$="tagger [[_computeHideTagger(item.tagger)]]">
<gr-account-link account="[[item.tagger]]"> </gr-account-link>
- (<gr-date-formatter
- has-tooltip=""
- date-str="[[item.tagger.date]]"
- >
+ (<gr-date-formatter withTooltip date-str="[[item.tagger.date]]">
</gr-date-formatter
>)
</div>
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
index 1af9c02..d5eb5d5 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
@@ -20,7 +20,11 @@
import 'lodash/lodash.js';
import {page} from '../../../utils/page-wrapper-utils.js';
import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi,
+} from '../../../test/test-utils.js';
import {RepoDetailView} from '../../core/gr-navigation/gr-navigation.js';
const basicFixture = fixtureFromElement('gr-repo-detail-list');
@@ -71,7 +75,7 @@
});
suite('list of repo branches', () => {
- setup(done => {
+ setup(async () => {
branches = [{
ref: 'HEAD',
revision: 'master',
@@ -82,53 +86,43 @@
repo: 'test',
detail: 'branches',
};
- element._paramsChanged(params).then(() => { flush(done); });
+ await element._paramsChanged(params);
+ await flush();
});
- test('test for branch in the list', done => {
- flush(() => {
- assert.equal(element._items[2].ref, 'refs/heads/test2');
- done();
- });
+ test('test for branch in the list', () => {
+ assert.equal(element._items[2].ref, 'refs/heads/test2');
});
- test('test for web links in the branches list', done => {
- flush(() => {
- assert.equal(element._items[2].web_links[0].url,
- 'https://git.example.org/branch/test;refs/heads/test2');
- done();
- });
+ test('test for web links in the branches list', () => {
+ assert.equal(element._items[2].web_links[0].url,
+ 'https://git.example.org/branch/test;refs/heads/test2');
});
- test('test for refs/heads/ being striped from ref', done => {
- flush(() => {
- assert.equal(element._stripRefs(element._items[2].ref,
- element.detailType), 'test2');
- done();
- });
+ test('test for refs/heads/ being striped from ref', () => {
+ assert.equal(element._stripRefs(element._items[2].ref,
+ element.detailType), 'test2');
});
test('_shownItems', () => {
assert.equal(element._shownItems.length, 25);
});
- test('Edit HEAD button not admin', done => {
+ test('Edit HEAD button not admin', async () => {
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
stubRestApi('getRepoAccess').returns(
Promise.resolve({
test: {is_owner: false},
}));
- element._determineIfOwner('test').then(() => {
- assert.equal(element._isOwner, false);
- assert.equal(getComputedStyle(dom(element.root)
- .querySelector('.revisionNoEditing')).display, 'inline');
- assert.equal(getComputedStyle(dom(element.root)
- .querySelector('.revisionEdit')).display, 'none');
- done();
- });
+ await element._determineIfOwner('test');
+ assert.equal(element._isOwner, false);
+ assert.equal(getComputedStyle(dom(element.root)
+ .querySelector('.revisionNoEditing')).display, 'inline');
+ assert.equal(getComputedStyle(dom(element.root)
+ .querySelector('.revisionEdit')).display, 'none');
});
- test('Edit HEAD button admin', done => {
+ test('Edit HEAD button admin', async () => {
const saveBtn = element.root.querySelector('.saveBtn');
const cancelBtn = element.root.querySelector('.cancelBtn');
const editBtn = element.root.querySelector('.editBtn');
@@ -143,76 +137,74 @@
test: {is_owner: true},
}));
sinon.stub(element, '_handleSaveRevision');
- element._determineIfOwner('test').then(() => {
- assert.equal(element._isOwner, true);
- // The revision container for non-editing enabled row is not visible.
- assert.equal(getComputedStyle(revisionNoEditing).display, 'none');
+ await element._determineIfOwner('test');
+ assert.equal(element._isOwner, true);
+ // The revision container for non-editing enabled row is not visible.
+ assert.equal(getComputedStyle(revisionNoEditing).display, 'none');
- // The revision container for editing enabled row is visible.
- assert.notEqual(getComputedStyle(dom(element.root)
- .querySelector('.revisionEdit')).display, 'none');
+ // The revision container for editing enabled row is visible.
+ assert.notEqual(getComputedStyle(dom(element.root)
+ .querySelector('.revisionEdit')).display, 'none');
- // The revision and edit button are visible.
- assert.notEqual(getComputedStyle(revisionWithEditing).display,
- 'none');
- assert.notEqual(getComputedStyle(editBtn).display, 'none');
+ // The revision and edit button are visible.
+ assert.notEqual(getComputedStyle(revisionWithEditing).display,
+ 'none');
+ assert.notEqual(getComputedStyle(editBtn).display, 'none');
- // The input, cancel, and save buttons are not visible.
- const hiddenElements = dom(element.root)
- .querySelectorAll('.canEdit .editItem');
+ // The input, cancel, and save buttons are not visible.
+ const hiddenElements = dom(element.root)
+ .querySelectorAll('.canEdit .editItem');
- for (const item of hiddenElements) {
- assert.equal(getComputedStyle(item).display, 'none');
- }
+ for (const item of hiddenElements) {
+ assert.equal(getComputedStyle(item).display, 'none');
+ }
- MockInteractions.tap(editBtn);
- flush();
- // The revision and edit button are not visible.
- assert.equal(getComputedStyle(revisionWithEditing).display, 'none');
- assert.equal(getComputedStyle(editBtn).display, 'none');
+ MockInteractions.tap(editBtn);
+ await flush();
+ // The revision and edit button are not visible.
+ assert.equal(getComputedStyle(revisionWithEditing).display, 'none');
+ assert.equal(getComputedStyle(editBtn).display, 'none');
- // The input, cancel, and save buttons are not visible.
- for (const item of hiddenElements) {
- assert.notEqual(getComputedStyle(item).display, 'none');
- }
+ // The input, cancel, and save buttons are not visible.
+ for (const item of hiddenElements) {
+ assert.notEqual(getComputedStyle(item).display, 'none');
+ }
- // The revised ref was set correctly
- assert.equal(element._revisedRef, 'master');
+ // The revised ref was set correctly
+ assert.equal(element._revisedRef, 'master');
- assert.isFalse(saveBtn.disabled);
+ assert.isFalse(saveBtn.disabled);
- // Delete the ref.
- element._revisedRef = '';
- assert.isTrue(saveBtn.disabled);
+ // Delete the ref.
+ element._revisedRef = '';
+ assert.isTrue(saveBtn.disabled);
- // Change the ref to something else
- element._revisedRef = 'newRef';
- element._repo = 'test';
- assert.isFalse(saveBtn.disabled);
+ // Change the ref to something else
+ element._revisedRef = 'newRef';
+ element._repo = 'test';
+ assert.isFalse(saveBtn.disabled);
- // Save button calls handleSave. since this is stubbed, the edit
- // section remains open.
- MockInteractions.tap(saveBtn);
- assert.isTrue(element._handleSaveRevision.called);
+ // Save button calls handleSave. since this is stubbed, the edit
+ // section remains open.
+ MockInteractions.tap(saveBtn);
+ assert.isTrue(element._handleSaveRevision.called);
- // When cancel is tapped, the edit secion closes.
- MockInteractions.tap(cancelBtn);
- flush();
+ // When cancel is tapped, the edit secion closes.
+ MockInteractions.tap(cancelBtn);
+ await flush();
- // The revision and edit button are visible.
- assert.notEqual(getComputedStyle(revisionWithEditing).display,
- 'none');
- assert.notEqual(getComputedStyle(editBtn).display, 'none');
+ // The revision and edit button are visible.
+ assert.notEqual(getComputedStyle(revisionWithEditing).display,
+ 'none');
+ assert.notEqual(getComputedStyle(editBtn).display, 'none');
- // The input, cancel, and save buttons are not visible.
- for (const item of hiddenElements) {
- assert.equal(getComputedStyle(item).display, 'none');
- }
- done();
- });
+ // The input, cancel, and save buttons are not visible.
+ for (const item of hiddenElements) {
+ assert.equal(getComputedStyle(item).display, 'none');
+ }
});
- test('_handleSaveRevision with invalid rev', done => {
+ test('_handleSaveRevision with invalid rev', async () => {
const event = {model: {set: sinon.stub()}};
element._isEditing = true;
stubRestApi('setRepoHead').returns(
@@ -221,14 +213,12 @@
})
);
- element._setRepoHead('test', 'newRef', event).then(() => {
- assert.isTrue(element._isEditing);
- assert.isFalse(event.model.set.called);
- done();
- });
+ await element._setRepoHead('test', 'newRef', event);
+ assert.isTrue(element._isEditing);
+ assert.isFalse(event.model.set.called);
});
- test('_handleSaveRevision with valid rev', done => {
+ test('_handleSaveRevision with valid rev', async () => {
const event = {model: {set: sinon.stub()}};
element._isEditing = true;
stubRestApi('setRepoHead').returns(
@@ -237,11 +227,9 @@
})
);
- element._setRepoHead('test', 'newRef', event).then(() => {
- assert.isFalse(element._isEditing);
- assert.isTrue(event.model.set.called);
- done();
- });
+ await element._setRepoHead('test', 'newRef', event);
+ assert.isFalse(element._isEditing);
+ assert.isTrue(event.model.set.called);
});
test('test _computeItemName', () => {
@@ -251,7 +239,7 @@
});
suite('list with less then 25 branches', () => {
- setup(done => {
+ setup(async () => {
branches = _.times(25, branchGenerator);
stubRestApi('getRepoBranches').returns(Promise.resolve(branches));
@@ -260,7 +248,8 @@
detail: 'branches',
};
- element._paramsChanged(params).then(() => { flush(done); });
+ await element._paramsChanged(params);
+ await flush();
});
test('_shownItems', () => {
@@ -287,16 +276,18 @@
});
suite('404', () => {
- test('fires page-error', done => {
+ test('fires page-error', async () => {
const response = {status: 404};
stubRestApi('getRepoBranches').callsFake(
(filter, repo, reposBranchesPerPage, opt_offset, errFn) => {
errFn(response);
+ return Promise.resolve();
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
const params = {
@@ -306,6 +297,7 @@
offset: 25,
};
element._paramsChanged(params);
+ await promise;
});
});
});
@@ -341,7 +333,7 @@
});
suite('list of repo tags', () => {
- setup(done => {
+ setup(async () => {
tags = _.times(26, tagGenerator);
stubRestApi('getRepoTags').returns(Promise.resolve(tags));
@@ -350,50 +342,37 @@
detail: 'tags',
};
- element._paramsChanged(params).then(() => { flush(done); });
+ await element._paramsChanged(params);
+ await flush();
});
- test('test for tag in the list', done => {
- flush(() => {
- assert.equal(element._items[1].ref, 'refs/tags/test2');
- done();
- });
+ test('test for tag in the list', async () => {
+ assert.equal(element._items[1].ref, 'refs/tags/test2');
});
- test('test for tag message in the list', done => {
- flush(() => {
- assert.equal(element._items[1].message, 'Annotated tag');
- done();
- });
+ test('test for tag message in the list', async () => {
+ assert.equal(element._items[1].message, 'Annotated tag');
});
- test('test for tagger in the tag list', done => {
+ test('test for tagger in the tag list', async () => {
const tagger = {
name: 'Test User',
email: 'test.user@gmail.com',
date: '2017-09-19 14:54:00.000000000',
tz: 540,
};
- flush(() => {
- assert.deepEqual(element._items[1].tagger, tagger);
- done();
- });
+
+ assert.deepEqual(element._items[1].tagger, tagger);
});
- test('test for web links in the tags list', done => {
- flush(() => {
- assert.equal(element._items[1].web_links[0].url,
- 'https://git.example.org/tag/test;refs/tags/test2');
- done();
- });
+ test('test for web links in the tags list', async () => {
+ assert.equal(element._items[1].web_links[0].url,
+ 'https://git.example.org/tag/test;refs/tags/test2');
});
- test('test for refs/tags/ being striped from ref', done => {
- flush(() => {
- assert.equal(element._stripRefs(element._items[1].ref,
- element.detailType), 'test2');
- done();
- });
+ test('test for refs/tags/ being striped from ref', async () => {
+ assert.equal(element._stripRefs(element._items[1].ref,
+ element.detailType), 'test2');
});
test('_shownItems', () => {
@@ -411,7 +390,7 @@
});
suite('list with less then 25 tags', () => {
- setup(done => {
+ setup(async () => {
tags = _.times(25, tagGenerator);
stubRestApi('getRepoTags').returns(Promise.resolve(tags));
@@ -420,7 +399,8 @@
detail: 'tags',
};
- element._paramsChanged(params).then(() => { flush(done); });
+ await element._paramsChanged(params);
+ await flush();
});
test('_shownItems', () => {
@@ -482,16 +462,18 @@
});
suite('404', () => {
- test('fires page-error', done => {
+ test('fires page-error', async () => {
const response = {status: 404};
stubRestApi('getRepoTags').callsFake(
(filter, repo, reposTagsPerPage, opt_offset, errFn) => {
errFn(response);
+ return Promise.resolve();
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.deepEqual(e.detail.response, response);
- done();
+ promise.resolve();
});
const params = {
@@ -501,6 +483,7 @@
offset: 25,
};
element._paramsChanged(params);
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
index 982fd8d..beef556 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
@@ -22,16 +22,16 @@
import '../gr-create-repo-dialog/gr-create-repo-dialog';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-repo-list_html';
-import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {customElement, property, observe, computed} from '@polymer/decorators';
import {AppElementAdminParams} from '../../gr-app-types';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
import {RepoName, ProjectInfoWithName} from '../../../types/common';
import {GrCreateRepoDialog} from '../gr-create-repo-dialog/gr-create-repo-dialog';
-import {ProjectState} from '../../../constants/constants';
+import {ProjectState, SHOWN_ITEMS_COUNT} from '../../../constants/constants';
import {fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {encodeURL, getBaseUrl} from '../../../utils/url-util';
declare global {
interface HTMLElementTagNameMap {
@@ -47,7 +47,7 @@
}
@customElement('gr-repo-list')
-export class GrRepoList extends ListViewMixin(PolymerElement) {
+export class GrRepoList extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -81,7 +81,7 @@
@computed('_repos')
get _shownRepos() {
- return this.computeShownItems(this._repos);
+ return this._repos.slice(0, SHOWN_ITEMS_COUNT);
}
private readonly restApiService = appContext.restApiService;
@@ -96,8 +96,8 @@
@observe('params')
_paramsChanged(params: AppElementAdminParams) {
this._loading = true;
- this._filter = this.getFilterValue(params);
- this._offset = this.getOffsetValue(params);
+ this._filter = params?.filter ?? '';
+ this._offset = Number(params?.offset ?? 0);
return this._getRepos(this._filter, this._reposPerPage, this._offset);
}
@@ -112,7 +112,7 @@
}
_computeRepoUrl(name: string) {
- return this.getUrl(this._path + '/', name);
+ return getBaseUrl() + this._path + '/' + encodeURL(name, true);
}
_computeChangesLink(name: string) {
@@ -182,4 +182,8 @@
const webLinks = repo.web_links;
return webLinks.length ? webLinks : null;
}
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
}
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
index 4864af5..8fef4d0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
@@ -53,17 +53,16 @@
});
suite('list with repos', () => {
- setup(done => {
+ setup(async () => {
repos = _.times(26, repoGenerator);
stubRestApi('getRepos').returns(Promise.resolve(repos));
- element._paramsChanged(value).then(() => { flush(done); });
+ await element._paramsChanged(value);
+ await flush();
});
- test('test for test repo in the list', done => {
- flush(() => {
- assert.equal(element._repos[1].id, 'test2');
- done();
- });
+ test('test for test repo in the list', async () => {
+ await flush();
+ assert.equal(element._repos[1].id, 'test2');
});
test('_shownRepos', () => {
@@ -84,10 +83,11 @@
});
suite('list with less then 25 repos', () => {
- setup(done => {
+ setup(async () => {
repos = _.times(25, repoGenerator);
stubRestApi('getRepos').returns(Promise.resolve(repos));
- element._paramsChanged(value).then(() => { flush(done); });
+ await element._paramsChanged(value);
+ await flush();
});
test('_shownRepos', () => {
@@ -113,17 +113,15 @@
assert.isTrue(repoStub.lastCall.calledWithExactly('test', 25, 25));
});
- test('latest repos requested are always set', done => {
+ test('latest repos requested are always set', async () => {
const repoStub = stubRestApi('getRepos');
repoStub.withArgs('test').returns(Promise.resolve(repos));
repoStub.withArgs('filter').returns(Promise.resolve(reposFiltered));
element._filter = 'test';
// Repos are not set because the element._filter differs.
- element._getRepos('filter', 25, 0).then(() => {
- assert.deepEqual(element._repos, []);
- done();
- });
+ await element._getRepos('filter', 25, 0);
+ assert.deepEqual(element._repos, []);
});
test('filter is case insensitive', async () => {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config-types.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config-types.ts
index 6a96f55..d5515f9 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config-types.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config-types.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
/**
- * @fileOverview This file contains interfaces shared between
+ * @fileoverview This file contains interfaces shared between
* gr-repo-plugin-config.ts and nested editors
* (e.g. gr-plugin-config-array-editor.ts)
*
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
index 42060ee..6e68ae7 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config.ts
@@ -23,8 +23,8 @@
import '../../shared/gr-select/gr-select';
import '../../shared/gr-tooltip-content/gr-tooltip-content';
import '../gr-plugin-config-array-editor/gr-plugin-config-array-editor';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {ConfigParameterInfoType} from '../../../constants/constants';
import {
ConfigParameterInfo,
@@ -57,7 +57,7 @@
}
@customElement('gr-repo-plugin-config')
-export class GrRepoPluginConfig extends GrLitElement {
+export class GrRepoPluginConfig extends LitElement {
/**
* Fired when the plugin config changes.
*
@@ -119,15 +119,7 @@
private renderOption(option: PluginOption) {
return html`
<section class="section ${option.info.type}">
- <span class="title">
- <gr-tooltip-content
- has-tooltip="${option.info.description}"
- show-icon="${option.info.description}"
- title="${option.info.description}"
- >
- <span>${option.info.display_name}</span>
- </gr-tooltip-content>
- </span>
+ <span class="title"> ${this.renderOptionTitle(option)} </span>
<span class="value">
${this.renderOptionDetail(option)} ${this.renderInherited(option)}
</span>
@@ -135,6 +127,18 @@
`;
}
+ private renderOptionTitle(option: PluginOption) {
+ const titleName = html`<span>${option.info.display_name}</span>`;
+ if (!option.info.description) return titleName;
+ return html` <gr-tooltip-content
+ has-tooltip
+ show-icon
+ title="${option.info.description}"
+ >
+ ${titleName}
+ </gr-tooltip-content>`;
+ }
+
private renderOptionDetail(option: PluginOption) {
if (option.info.type === ConfigParameterInfoType.ARRAY) {
return html`
@@ -149,7 +153,7 @@
?checked=${this._computeChecked(option.info.value)}
@change=${this._handleBooleanChange}
data-option-key=${option._key}
- ?disabled=${option.info.editable}
+ ?disabled=${!option.info.editable}
@click=${this._onTapPluginBoolean}
></paper-toggle-button>
`;
@@ -158,7 +162,7 @@
<gr-select value=${option.info.value} @change=${this._handleListChange}>
<select
data-option-key=${option._key}
- ?disabled=${option.info.editable}
+ ?disabled=${!option.info.editable}
>
${(option.info.permitted_values || []).map(
value => html`<option value="${value}">${value}</option>`
@@ -176,14 +180,14 @@
value=${option.info.value}
@input=${this._handleStringChange}
data-option-key="${option._key}"
- ?disabled=${option.info.editable}
+ ?disabled=${!option.info.editable}
>
<input
is="iron-input"
- value="${option.info.value}"
+ .value="${option.info.value}"
@input=${this._handleStringChange}
data-option-key="${option._key}"
- ?disabled=${option.info.editable}
+ ?disabled=${!option.info.editable}
/>
</iron-input>
`;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.js b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.js
index 17e8256..8c2e6b3 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-plugin-config/gr-repo-plugin-config_test.js
@@ -67,7 +67,7 @@
test('ARRAY type option', async () => {
element.pluginData = {
name: 'testName',
- config: {plugin: {value: 'test', type: 'ARRAY'}},
+ config: {plugin: {value: 'test', type: 'ARRAY', editable: true}},
};
await flush();
@@ -82,7 +82,7 @@
test('BOOLEAN type option', async () => {
element.pluginData = {
name: 'testName',
- config: {plugin: {value: 'true', type: 'BOOLEAN'}},
+ config: {plugin: {value: 'true', type: 'BOOLEAN', editable: true}},
};
await flush();
@@ -101,7 +101,7 @@
test('INT/LONG/STRING type option', async () => {
element.pluginData = {
name: 'testName',
- config: {plugin: {value: 'test', type: 'STRING'}},
+ config: {plugin: {value: 'test', type: 'STRING', editable: true}},
};
await flush();
@@ -122,7 +122,9 @@
const permitted_values = ['test', 'newTest'];
element.pluginData = {
name: 'testName',
- config: {plugin: {value: 'test', type: 'LIST', permitted_values}},
+ config: {plugin:
+ {value: 'test', type: 'LIST', editable: true, permitted_values},
+ },
};
await flush();
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 d132267..cd5b095 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -20,6 +20,7 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../shared/gr-download-commands/gr-download-commands';
import '../../shared/gr-select/gr-select';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-subpage-styles';
import '../../../styles/shared-styles';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
index ef0e6b4..71abec0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
index 9c3646a..f3df132 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_test.js
@@ -180,7 +180,7 @@
});
suite('already existing generic rule', () => {
- setup(done => {
+ setup(async () => {
element.group = 'Group Name';
element.permission = 'submit';
element.rule = {
@@ -195,11 +195,8 @@
// Typically called on ready since elements will have properties defined
// by the parent element.
element._setupValues(element.rule);
- flush();
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -295,7 +292,7 @@
});
suite('new edit rule', () => {
- setup(done => {
+ setup(async () => {
element.group = 'Group Name';
element.permission = 'editTopicName';
element.rule = {
@@ -303,12 +300,10 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
+ await flush();
element.rule.value.added = true;
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -348,7 +343,7 @@
});
suite('already existing rule with labels', () => {
- setup(done => {
+ setup(async () => {
element.label = {values: [
{value: -2, text: 'This shall not be merged'},
{value: -1, text: 'I would prefer this is not merged as is'},
@@ -369,11 +364,8 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -406,7 +398,7 @@
});
suite('new rule with labels', () => {
- setup(done => {
+ setup(async () => {
sinon.spy(element, '_setDefaultRuleValues');
element.label = {values: [
{value: -2, text: 'This shall not be merged'},
@@ -422,12 +414,10 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
+ await flush();
element.rule.value.added = true;
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -468,7 +458,7 @@
});
suite('already existing push rule', () => {
- setup(done => {
+ setup(async () => {
element.group = 'Group Name';
element.permission = 'push';
element.rule = {
@@ -480,11 +470,8 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -513,7 +500,7 @@
});
suite('new push rule', () => {
- setup(done => {
+ setup(async () => {
element.group = 'Group Name';
element.permission = 'push';
element.rule = {
@@ -521,12 +508,10 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
+ await flush();
element.rule.value.added = true;
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -557,7 +542,7 @@
});
suite('already existing edit rule', () => {
- setup(done => {
+ setup(async () => {
element.group = 'Group Name';
element.permission = 'editTopicName';
element.rule = {
@@ -569,11 +554,8 @@
};
element.section = 'refs/*';
element._setupValues(element.rule);
- flush();
- flush(() => {
- element.connectedCallback();
- done();
- });
+ await flush();
+ element.connectedCallback();
});
test('_ruleValues and _originalRuleValues are set correctly', () => {
@@ -590,10 +572,10 @@
assert.isNotOk(element.root.querySelector('#labelMax'));
});
- test('modify value', () => {
+ test('modify value', async () => {
assert.isNotOk(element.rule.value.modified);
element.$.action.bindValue = false;
- flush();
+ await flush();
assert.isTrue(element.rule.value.modified);
// The original value should now differ from the rule values.
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
index 50bbda9..c476d2d 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.ts
@@ -28,7 +28,6 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-list-item_html';
-import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {getDisplayName} from '../../../utils/display-name-util';
import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
@@ -77,7 +76,7 @@
const PRIMARY_REVIEWERS_COUNT = 2;
@customElement('gr-change-list-item')
-export class GrChangeListItem extends ChangeTableMixin(PolymerElement) {
+export class GrChangeListItem extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -285,7 +284,7 @@
* @param truncate whether or not the project name should be
* truncated. If this value is truthy, the name will be truncated.
*/
- _computeRepoDisplay(change: ChangeInfo | undefined, truncate: boolean) {
+ _computeRepoDisplay(change?: ChangeInfo) {
if (!change?.project) {
return '';
}
@@ -293,7 +292,19 @@
if (change.internalHost) {
str += change.internalHost + '/';
}
- str += truncate ? truncatePath(change.project, 2) : change.project;
+ str += change.project;
+ return str;
+ }
+
+ _computeTruncatedRepoDisplay(change?: ChangeInfo) {
+ if (!change?.project) {
+ return '';
+ }
+ let str = '';
+ if (change.internalHost) {
+ str += change.internalHost + '/';
+ }
+ str += truncatePath(change.project, 2);
return str;
}
@@ -351,10 +362,7 @@
return this._computeAdditionalReviewers(change).length;
}
- _computeAdditionalReviewersTitle(
- change: ChangeInfo | undefined,
- config: ServerInfo
- ) {
+ _computeAdditionalReviewersTitle(change?: ChangeInfo, config?: ServerInfo) {
if (!change || !config) return '';
return this._computeAdditionalReviewers(change)
.map(user => getDisplayName(config, user, true))
@@ -390,13 +398,20 @@
}
_computeWaiting(
- account?: AccountInfo,
- change?: ChangeInfo
+ account?: AccountInfo | null,
+ change?: ChangeInfo | null
): Timestamp | undefined {
if (!account?._account_id || !change?.attention_set) return undefined;
return change?.attention_set[account._account_id]?.last_update;
}
+ _computeIsColumnHidden(columnToCheck?: string, columnsToDisplay?: string[]) {
+ if (!columnsToDisplay || !columnToCheck) {
+ return false;
+ }
+ return !columnsToDisplay.includes(columnToCheck);
+ }
+
toggleReviewed() {
if (!this.change) return;
const newVal = !this.change?.reviewed;
@@ -414,6 +429,11 @@
);
}
+ _formatDate(date: Timestamp | undefined): string | undefined {
+ if (!date) return undefined;
+ return date.toString();
+ }
+
_handleChangeClick() {
// Don't prevent the default and neither stop bubbling. We just want to
// report the click, but then let the browser handle the click on the link.
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
index 8ee6a3f..e1013e1 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.ts
@@ -127,7 +127,7 @@
</td>
<td
class="cell subject"
- hidden$="[[isColumnHidden('Subject', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Subject', visibleChangeTableColumns)]]"
>
<a
title$="[[change.subject]]"
@@ -143,7 +143,7 @@
</td>
<td
class="cell status"
- hidden$="[[isColumnHidden('Status', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Status', visibleChangeTableColumns)]]"
>
<template is="dom-repeat" items="[[statuses]]" as="status">
<div class="comma">,</div>
@@ -155,7 +155,7 @@
</td>
<td
class="cell owner"
- hidden$="[[isColumnHidden('Owner', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Owner', visibleChangeTableColumns)]]"
>
<gr-account-link
highlightAttention
@@ -165,7 +165,7 @@
</td>
<td
class="cell assignee"
- hidden$="[[isColumnHidden('Assignee', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Assignee', visibleChangeTableColumns)]]"
>
<template is="dom-if" if="[[change.assignee]]">
<gr-account-link
@@ -179,7 +179,7 @@
</td>
<td
class="cell reviewers"
- hidden$="[[isColumnHidden('Reviewers', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Reviewers', visibleChangeTableColumns)]]"
>
<div>
<template
@@ -204,14 +204,14 @@
</template>
<template is="dom-if" if="[[_computeAdditionalReviewersCount(change)]]">
<span title="[[_computeAdditionalReviewersTitle(change, config)]]">
- +[[_computeAdditionalReviewersCount(change, config)]]
+ +[[_computeAdditionalReviewersCount(change)]]
</span>
</template>
</div>
</td>
<td
class="cell comments"
- hidden$="[[isColumnHidden('Comments', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Comments', visibleChangeTableColumns)]]"
>
<iron-icon
hidden$="[[!change.unresolved_comment_count]]"
@@ -221,22 +221,22 @@
</td>
<td
class="cell repo"
- hidden$="[[isColumnHidden('Repo', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Repo', visibleChangeTableColumns)]]"
>
<a class="fullRepo" href$="[[_computeRepoUrl(change)]]">
- [[_computeRepoDisplay(change)]]
+ <div class="content">[[_computeRepoDisplay(change)]]</div>
</a>
<a
class="truncatedRepo"
href$="[[_computeRepoUrl(change)]]"
title$="[[_computeRepoDisplay(change)]]"
>
- [[_computeRepoDisplay(change, 'true')]]
+ [[_computeTruncatedRepoDisplay(change)]]
</a>
</td>
<td
class="cell branch"
- hidden$="[[isColumnHidden('Branch', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Branch', visibleChangeTableColumns)]]"
>
<a href$="[[_computeRepoBranchURL(change)]]"> [[change.branch]] </a>
<template is="dom-if" if="[[change.topic]]">
@@ -250,38 +250,38 @@
</td>
<td
class="cell updated"
- hidden$="[[isColumnHidden('Updated', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Updated', visibleChangeTableColumns)]]"
>
<gr-date-formatter
- has-tooltip=""
- date-str="[[change.updated]]"
+ withTooltip
+ date-str="[[_formatDate(change.updated)]]"
></gr-date-formatter>
</td>
<td
class="cell submitted"
- hidden$="[[isColumnHidden('Submitted', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Submitted', visibleChangeTableColumns)]]"
>
<gr-date-formatter
- has-tooltip=""
- date-str="[[change.submitted]]"
+ withTooltip
+ date-str="[[_formatDate(change.submitted)]]"
></gr-date-formatter>
</td>
<td
class="cell waiting"
- hidden$="[[isColumnHidden('Waiting', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Waiting', visibleChangeTableColumns)]]"
>
<gr-date-formatter
- has-tooltip=""
- force-relative=""
- relative-option-no-ago=""
+ withTooltip
+ forceRelative
+ relativeOptionNoAge
date-str="[[_computeWaiting(account, change)]]"
></gr-date-formatter>
</td>
<td
class="cell size"
- hidden$="[[isColumnHidden('Size', visibleChangeTableColumns)]]"
+ hidden$="[[_computeIsColumnHidden('Size', visibleChangeTableColumns)]]"
>
- <gr-tooltip-content has-tooltip="" title="[[_computeSizeTooltip(change)]]">
+ <gr-tooltip-content has-tooltip title="[[_computeSizeTooltip(change)]]">
<template is="dom-if" if="[[_changeSize]]">
<span>[[_changeSize]]</span>
</template>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts
index ac0b929..34cb6eb 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.ts
@@ -29,6 +29,7 @@
TopicName,
} from '../../../types/common';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
+import {columnNames} from '../gr-change-list/gr-change-list';
import './gr-change-list-item';
import {GrChangeListItem, LabelCategory} from './gr-change-list-item';
@@ -372,7 +373,7 @@
await flush();
- for (const column of element.columnNames) {
+ for (const column of columnNames) {
const elementClass = '.' + column.toLowerCase();
assert.isFalse(
queryAndAssert(element, elementClass).hasAttribute('hidden')
@@ -395,7 +396,7 @@
await flush();
- for (const column of element.columnNames) {
+ for (const column of columnNames) {
const elementClass = '.' + column.toLowerCase();
if (column === 'Repo') {
assert.isTrue(
@@ -565,13 +566,13 @@
});
test('_computeRepoDisplay', () => {
+ assert.equal(element._computeRepoDisplay(change), 'host/a/test/repo');
assert.equal(
- element._computeRepoDisplay(change, false),
- 'host/a/test/repo'
+ element._computeTruncatedRepoDisplay(change),
+ 'host/…/test/repo'
);
- assert.equal(element._computeRepoDisplay(change, true), 'host/…/test/repo');
delete change.internalHost;
- assert.equal(element._computeRepoDisplay(change, false), 'a/test/repo');
- assert.equal(element._computeRepoDisplay(change, true), '…/test/repo');
+ assert.equal(element._computeRepoDisplay(change), 'a/test/repo');
+ assert.equal(element._computeTruncatedRepoDisplay(change), '…/test/repo');
});
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
index 9970dd5..2360312 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
@@ -39,6 +39,7 @@
import {fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
import {GerritView} from '../../../services/router/router-model';
+import {RELOAD_DASHBOARD_INTERVAL_MS} from '../../../constants/constants';
const LOOKUP_QUERY_PATTERNS: RegExp[] = [
/^\s*i?[0-9a-f]{7,40}\s*$/i, // CHANGE_ID
@@ -112,10 +113,26 @@
private reporting = appContext.reportingService;
+ private lastVisibleTimestampMs = 0;
+
constructor() {
super();
this.addEventListener('next-page', () => this._handleNextPage());
this.addEventListener('previous-page', () => this._handlePreviousPage());
+ this.addEventListener('reload', () => this.reload());
+ // We are not currently verifying if the view is actually visible. We rely
+ // on gr-app-element to restamp the component if view changes
+ document.addEventListener('visibilitychange', () => {
+ if (document.visibilityState === 'visible') {
+ if (
+ Date.now() - this.lastVisibleTimestampMs >
+ RELOAD_DASHBOARD_INTERVAL_MS
+ )
+ this.reload();
+ } else {
+ this.lastVisibleTimestampMs = Date.now();
+ }
+ });
}
override connectedCallback() {
@@ -123,6 +140,15 @@
this._loadPreferences();
}
+ reload() {
+ if (this._loading) return;
+ this._loading = true;
+ this._getChanges().then(changes => {
+ this._changes = changes || [];
+ this._loading = false;
+ });
+ }
+
_paramsChanged(value: AppElementParams) {
if (value.view !== GerritView.SEARCH) return;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
index 54d3911..355ef45 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
@@ -66,7 +66,7 @@
></gr-repo-header>
<gr-user-header
user-id="[[_userId]]"
- show-dashboard-link=""
+ showDashboardLink=""
logged-in="[[_loggedIn]]"
class$="[[_computeHeaderClass(_userId)]]"
></gr-user-header>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js
index 445254a..86b2fd1 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_test.js
@@ -20,7 +20,7 @@
import {page} from '../../../utils/page-wrapper-utils.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
import 'lodash/lodash.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {mockPromise, stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-change-list-view');
@@ -38,10 +38,8 @@
element = basicFixture.instantiate();
});
- teardown(done => {
- flush(() => {
- done();
- });
+ teardown(async () => {
+ await flush();
});
test('_computePage', () => {
@@ -126,128 +124,123 @@
assert.isTrue(showStub.called);
});
- test('_userId query', done => {
+ test('_userId query', async () => {
assert.isNull(element._userId);
element._query = 'owner: foo@bar';
element._changes = [{owner: {email: 'foo@bar'}}];
- flush(() => {
- assert.equal(element._userId, 'foo@bar');
+ await flush();
+ assert.equal(element._userId, 'foo@bar');
- element._query = 'foo bar baz';
- element._changes = [{owner: {email: 'foo@bar'}}];
- assert.isNull(element._userId);
-
- done();
- });
+ element._query = 'foo bar baz';
+ element._changes = [{owner: {email: 'foo@bar'}}];
+ assert.isNull(element._userId);
});
- test('_userId query without email', done => {
+ test('_userId query without email', async () => {
assert.isNull(element._userId);
element._query = 'owner: foo@bar';
element._changes = [{owner: {}}];
- flush(() => {
- assert.isNull(element._userId);
- done();
- });
+ await flush();
+ assert.isNull(element._userId);
});
- test('_repo query', done => {
+ test('_repo query', async () => {
assert.isNull(element._repo);
element._query = 'project: test-repo';
element._changes = [{owner: {email: 'foo@bar'}, project: 'test-repo'}];
- flush(() => {
- assert.equal(element._repo, 'test-repo');
- element._query = 'foo bar baz';
- element._changes = [{owner: {email: 'foo@bar'}}];
- assert.isNull(element._repo);
- done();
- });
+ await flush();
+ assert.equal(element._repo, 'test-repo');
+ element._query = 'foo bar baz';
+ element._changes = [{owner: {email: 'foo@bar'}}];
+ assert.isNull(element._repo);
});
- test('_repo query with open status', done => {
+ test('_repo query with open status', async () => {
assert.isNull(element._repo);
element._query = 'project:test-repo status:open';
element._changes = [{owner: {email: 'foo@bar'}, project: 'test-repo'}];
- flush(() => {
- assert.equal(element._repo, 'test-repo');
- element._query = 'foo bar baz';
- element._changes = [{owner: {email: 'foo@bar'}}];
- assert.isNull(element._repo);
- done();
- });
+ await flush();
+ assert.equal(element._repo, 'test-repo');
+ element._query = 'foo bar baz';
+ element._changes = [{owner: {email: 'foo@bar'}}];
+ assert.isNull(element._repo);
});
suite('query based navigation', () => {
setup(() => {
});
- teardown(done => {
- flush(() => {
- sinon.restore();
- done();
- });
+ teardown(async () => {
+ await flush();
+ sinon.restore();
});
- test('Searching for a change ID redirects to change', done => {
+ test('Searching for a change ID redirects to change', async () => {
const change = {_number: 1};
sinon.stub(element, '_getChanges')
.returns(Promise.resolve([change]));
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake(
(url, opt_patchNum, opt_basePatchNum, opt_isEdit, opt_redirect) => {
assert.equal(url, change);
assert.isTrue(opt_redirect);
- done();
+ promise.resolve();
});
element.params = {view: GerritNav.View.SEARCH, query: CHANGE_ID};
+ await promise;
});
- test('Searching for a change num redirects to change', done => {
+ test('Searching for a change num redirects to change', async () => {
const change = {_number: 1};
sinon.stub(element, '_getChanges')
.returns(Promise.resolve([change]));
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake(
(url, opt_patchNum, opt_basePatchNum, opt_isEdit, opt_redirect) => {
assert.equal(url, change);
assert.isTrue(opt_redirect);
- done();
+ promise.resolve();
});
element.params = {view: GerritNav.View.SEARCH, query: '1'};
+ await promise;
});
- test('Commit hash redirects to change', done => {
+ test('Commit hash redirects to change', async () => {
const change = {_number: 1};
sinon.stub(element, '_getChanges')
.returns(Promise.resolve([change]));
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake(
(url, opt_patchNum, opt_basePatchNum, opt_isEdit, opt_redirect) => {
assert.equal(url, change);
assert.isTrue(opt_redirect);
- done();
+ promise.resolve();
});
element.params = {view: GerritNav.View.SEARCH, query: COMMIT_HASH};
+ await promise;
});
- test('Searching for an invalid change ID searches', () => {
+ test('Searching for an invalid change ID searches', async () => {
sinon.stub(element, '_getChanges')
.returns(Promise.resolve([]));
const stub = sinon.stub(GerritNav, 'navigateToChange');
element.params = {view: GerritNav.View.SEARCH, query: CHANGE_ID};
- flush();
+ await flush();
assert.isFalse(stub.called);
});
- test('Change ID with multiple search results searches', () => {
+ test('Change ID with multiple search results searches', async () => {
sinon.stub(element, '_getChanges')
.returns(Promise.resolve([{}, {}]));
const stub = sinon.stub(GerritNav, 'navigateToChange');
element.params = {view: GerritNav.View.SEARCH, query: CHANGE_ID};
- flush();
+ await flush();
assert.isFalse(stub.called);
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index 5c0bab8..a2a46e0 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -24,7 +24,6 @@
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-list_html';
import {appContext} from '../../../services/app-context';
-import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
import {
KeyboardShortcutMixin,
Shortcut,
@@ -57,18 +56,34 @@
const LABEL_PREFIX_INVALID_PROLOG = 'Invalid-Prolog-Rules-Label-Name--';
const MAX_SHORTCUT_CHARS = 5;
+export const columnNames = [
+ 'Subject',
+ 'Status',
+ 'Owner',
+ 'Assignee',
+ 'Reviewers',
+ 'Comments',
+ 'Repo',
+ 'Branch',
+ 'Updated',
+ 'Size',
+];
+
export interface ChangeListSection {
name?: string;
query?: string;
results: ChangeInfo[];
}
+
export interface GrChangeList {
$: {};
}
+
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-change-list')
-export class GrChangeList extends ChangeTableMixin(
- KeyboardShortcutMixin(PolymerElement)
-) {
+export class GrChangeList extends base {
static get template() {
return htmlTemplate;
}
@@ -216,32 +231,44 @@
return;
}
- this.changeTableColumns = this.columnNames;
+ this.changeTableColumns = columnNames;
this.showNumber = false;
- this.visibleChangeTableColumns = this.getEnabledColumns(
- this.columnNames,
- config,
- this.flagsService.enabledExperiments
+ this.visibleChangeTableColumns = this.changeTableColumns.filter(col =>
+ this._isColumnEnabled(col, config, this.flagsService.enabledExperiments)
);
-
if (account && preferences) {
this.showNumber = !!(
preferences && preferences.legacycid_in_change_table
);
if (preferences.change_table && preferences.change_table.length > 0) {
- const prefColumns = this.renameProjectToRepoColumn(
- preferences.change_table
+ const prefColumns = preferences.change_table.map(column =>
+ column === 'Project' ? 'Repo' : column
);
- this.visibleChangeTableColumns = this.getEnabledColumns(
- prefColumns,
- config,
- this.flagsService.enabledExperiments
+ this.visibleChangeTableColumns = prefColumns.filter(col =>
+ this._isColumnEnabled(
+ col,
+ config,
+ this.flagsService.enabledExperiments
+ )
);
}
}
}
/**
+ * Is the column disabled by a server config or experiment? For example the
+ * assignee feature might be disabled and thus the corresponding column is
+ * also disabled.
+ *
+ */
+ _isColumnEnabled(column: string, config: ServerInfo, experiments: string[]) {
+ if (!config || !config.change) return true;
+ if (column === 'Assignee') return !!config.change.enable_assignee;
+ if (column === 'Comments') return experiments.includes('comments-column');
+ return true;
+ }
+
+ /**
* This methods allows us to customize the columns per section.
*
* @param visibleColumns are the columns according to configs and user prefs
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
index 37d969e..c31da77 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
@@ -63,7 +63,7 @@
class="cell"
colspan$="[[_computeColspan(changeSection, visibleChangeTableColumns, labelNames)]]"
>
- <h2>
+ <h2 class="heading-3">
<a
href$="[[_sectionHref(changeSection.query)]]"
class="section-title"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.js
index 13490d7..7b226e7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.js
@@ -19,7 +19,7 @@
import './gr-change-list.js';
import {afterNextRender} from '@polymer/polymer/lib/utils/render-status.js';
import {GerritNav} from '../../core/gr-navigation/gr-navigation.js';
-import {TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
+import {mockPromise, TestKeyboardShortcutBinder} from '../../../test/test-utils.js';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js';
import {YOUR_TURN} from '../../core/gr-navigation/gr-navigation.js';
@@ -149,7 +149,7 @@
{}, changeTableColumns, labelNames));
});
- test('keyboard shortcuts', done => {
+ test('keyboard shortcuts', async () => {
sinon.stub(element, '_computeLabelNames');
element.sections = [
{results: new Array(1)},
@@ -161,7 +161,8 @@
{_number: 1},
{_number: 2},
];
- flush();
+ await flush();
+ const promise = mockPromise();
afterNextRender(element, () => {
const elementItems = element.root.querySelectorAll(
'gr-change-list-item');
@@ -192,8 +193,9 @@
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
assert.equal(element.selectedIndex, 0);
- done();
+ promise.resolve();
});
+ await promise;
});
test('no changes', () => {
@@ -267,7 +269,7 @@
});
test('all columns visible', () => {
- for (const column of element.columnNames) {
+ for (const column of element.changeTableColumns) {
const elementClass = '.' + element._lowerCase(column);
assert.isFalse(element.shadowRoot
.querySelector(elementClass).hidden);
@@ -436,7 +438,7 @@
element = basicFixture.instantiate();
});
- test('keyboard shortcuts', done => {
+ test('keyboard shortcuts', async () => {
element.selectedIndex = 0;
element.sections = [
{
@@ -461,7 +463,8 @@
],
},
];
- flush();
+ await flush();
+ const promise = mockPromise();
afterNextRender(element, () => {
const elementItems = element.root.querySelectorAll(
'gr-change-list-item');
@@ -499,8 +502,9 @@
MockInteractions.pressAndReleaseKeyOn(element, 82); // 'r'
assert.equal(change.reviewed, false,
'Should mark change as unreviewed');
- done();
+ promise.resolve();
});
+ await promise;
});
test('_computeItemHighlight gives false for null account', () => {
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
index 055996ee..fd2a5d7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help.ts
@@ -19,8 +19,9 @@
import '../../shared/gr-icons/gr-icons';
import {fireEvent} from '../../../utils/event-util';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement} from 'lit/decorators';
+import {fontStyles} from '../../../styles/gr-font-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -29,10 +30,11 @@
}
@customElement('gr-create-change-help')
-export class GrCreateChangeHelp extends GrLitElement {
+export class GrCreateChangeHelp extends LitElement {
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.ts b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.ts
index 1a359e5..e170a74 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-change-help/gr-create-change-help_test.ts
@@ -18,7 +18,7 @@
import '../../../test/common-test-setup-karma';
import './gr-create-change-help';
import {GrCreateChangeHelp} from './gr-create-change-help';
-import {queryAndAssert} from '../../../test/test-utils';
+import {mockPromise, queryAndAssert} from '../../../test/test-utils';
import {GrButton} from '../../shared/gr-button/gr-button';
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
@@ -32,8 +32,10 @@
await flush();
});
- test('Create change tap', done => {
- element.addEventListener('create-tap', () => done());
+ test('Create change tap', async () => {
+ const promise = mockPromise();
+ element.addEventListener('create-tap', () => promise.resolve());
MockInteractions.tap(queryAndAssert<GrButton>(element, 'gr-button'));
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
index 171c1c3..6c9fa68 100644
--- a/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-create-commands-dialog/gr-create-commands-dialog.ts
@@ -20,8 +20,8 @@
import '../../shared/gr-shell-command/gr-shell-command';
import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, query} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property, query} from 'lit/decorators';
enum Commands {
CREATE = 'git commit',
@@ -36,7 +36,7 @@
}
@customElement('gr-create-commands-dialog')
-export class GrCreateCommandsDialog extends GrLitElement {
+export class GrCreateCommandsDialog extends LitElement {
@query('#commandsOverlay')
commandsOverlay?: GrOverlay;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
index c341dea..9eca3bc 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../gr-change-list/gr-change-list';
import '../../shared/gr-button/gr-button';
@@ -54,9 +55,9 @@
import {DashboardViewState} from '../../../types/types';
import {firePageError, fireTitleChange} from '../../../utils/event-util';
import {GerritView} from '../../../services/router/router-model';
+import {RELOAD_DASHBOARD_INTERVAL_MS} from '../../../constants/constants';
const PROJECT_PLACEHOLDER_PATTERN = /\${project}/g;
-const RELOAD_DASHBOARD_INTERVAL_MS = 10 * 1000;
export interface GrDashboardView {
$: {
@@ -122,12 +123,9 @@
constructor() {
super();
- }
-
- override connectedCallback() {
- super.connectedCallback();
- this._loadPreferences();
this.addEventListener('reload', () => this._reload(this.params));
+ // We are not currently verifying if the view is actually visible. We rely
+ // on gr-app-element to restamp the component if view changes
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
if (
@@ -141,6 +139,11 @@
});
}
+ override connectedCallback() {
+ super.connectedCallback();
+ this._loadPreferences();
+ }
+
_loadPreferences() {
return this.restApiService.getLoggedIn().then(loggedIn => {
if (loggedIn) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
index 484a952..4778890 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
index 473d2b9..96a19e0 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
@@ -22,7 +22,7 @@
import {changeIsOpen} from '../../../utils/change-util.js';
import {ChangeStatus} from '../../../constants/constants.js';
import {createAccountWithId} from '../../../test/test-data-generators.js';
-import {addListenerForTest, stubRestApi, isHidden} from '../../../test/test-utils.js';
+import {addListenerForTest, stubRestApi, isHidden, mockPromise} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-dashboard-view');
@@ -395,21 +395,23 @@
'hide');
});
- test('404 page', done => {
+ test('404 page', async () => {
const response = {status: 404};
stubRestApi('getDashboard').callsFake(
async (project, dashboard, errFn) => {
errFn(response);
});
+ const promise = mockPromise();
addListenerForTest(document, 'page-error', e => {
assert.strictEqual(e.detail.response, response);
- paramsChangedPromise.then(done);
+ promise.resolve();
});
element.params = {
view: GerritNav.View.DASHBOARD,
project: 'project',
dashboard: 'dashboard',
};
+ await Promise.all([paramsChangedPromise, promise]);
});
test('params change triggers dashboardDisplayed()', async () => {
@@ -427,7 +429,7 @@
assert.isTrue(element.reporting.dashboardDisplayed.calledOnce);
});
- test('selectedChangeIndex is derived from the params', () => {
+ test('selectedChangeIndex is derived from the params', async () => {
stubRestApi('getDashboard').returns(Promise.resolve({
title: 'title',
sections: [],
@@ -443,9 +445,8 @@
};
flush();
sinon.stub(element.reporting, 'dashboardDisplayed');
- paramsChangedPromise.then(() => {
- assert.equal(element._selectedChangeIndex, 23);
- });
+ await paramsChangedPromise;
+ assert.equal(element._selectedChangeIndex, 23);
});
});
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
index 7b60715..9242a58 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header.ts
@@ -15,18 +15,18 @@
* limitations under the License.
*/
-import '../../shared/gr-date-formatter/gr-date-formatter';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {RepoName} from '../../../types/common';
import {WebLinkInfo} from '../../../types/diff';
import {appContext} from '../../../services/app-context';
import {sharedStyles} from '../../../styles/shared-styles';
+import {fontStyles} from '../../../styles/gr-font-styles';
import {dashboardHeaderStyles} from '../../../styles/dashboard-header-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, PropertyValues} from 'lit-element';
+import {LitElement, css, html, PropertyValues} from 'lit';
+import {customElement, property} from 'lit/decorators';
@customElement('gr-repo-header')
-export class GrRepoHeader extends GrLitElement {
+export class GrRepoHeader extends LitElement {
@property({type: String})
repo?: RepoName;
@@ -42,6 +42,7 @@
return [
sharedStyles,
dashboardHeaderStyles,
+ fontStyles,
css`
.browse {
display: inline-block;
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
index 4c42005..e87b4f9 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
@@ -25,11 +25,12 @@
import {appContext} from '../../../services/app-context';
import {dashboardHeaderStyles} from '../../../styles/dashboard-header-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, PropertyValues} from 'lit-element';
+import {fontStyles} from '../../../styles/gr-font-styles';
+import {LitElement, css, html, PropertyValues} from 'lit';
+import {customElement, property} from 'lit/decorators';
@customElement('gr-user-header')
-export class GrUserHeader extends GrLitElement {
+export class GrUserHeader extends LitElement {
@property({type: String})
userId?: AccountId;
@@ -47,10 +48,11 @@
private readonly restApiService = appContext.restApiService;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
dashboardHeaderStyles,
+ fontStyles,
css`
.status.hide,
.name.hide,
@@ -61,7 +63,7 @@
];
}
- render() {
+ override render() {
return html` <gr-avatar
.account="${this._accountDetails}"
.imageSize=${100}
@@ -114,7 +116,7 @@
</div>`;
}
- updated(changedProperties: PropertyValues) {
+ override updated(changedProperties: PropertyValues) {
if (changedProperties.has('userId')) {
this._accountChanged(this.userId);
}
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 081df40..891482d 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
@@ -1190,6 +1190,13 @@
});
}
+ showSubmitDialog() {
+ if (!this._canSubmitChange()) {
+ return;
+ }
+ this._showActionDialog(this.$.confirmSubmitDialog);
+ }
+
_handleActionTap(e: MouseEvent) {
e.preventDefault();
let el = (dom(e) as EventApi).localTarget as Element;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
index 614339a..b5f55ca 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
@@ -84,24 +84,27 @@
hidden$="[[_shouldHideActions(_topLevelActions.*, _loading)]]"
>
<template is="dom-repeat" items="[[_topLevelPrimaryActions]]" as="action">
- <gr-button
- link=""
+ <gr-tooltip-content
title$="[[action.title]]"
has-tooltip="[[_computeHasTooltip(action.title)]]"
position-below="true"
- data-action-key$="[[action.__key]]"
- class$="[[action.__key]]"
- data-action-type$="[[action.__type]]"
- data-label$="[[action.label]]"
- disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
- on-click="_handleActionTap"
>
- <iron-icon
- class$="[[_computeHasIcon(action)]]"
- icon$="gr-icons:[[action.icon]]"
- ></iron-icon>
- [[action.label]]
- </gr-button>
+ <gr-button
+ link=""
+ data-action-key$="[[action.__key]]"
+ class$="[[action.__key]]"
+ data-action-type$="[[action.__type]]"
+ data-label$="[[action.label]]"
+ disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
+ on-click="_handleActionTap"
+ >
+ <iron-icon
+ class$="[[_computeHasIcon(action)]]"
+ icon$="gr-icons:[[action.icon]]"
+ ></iron-icon>
+ [[action.label]]
+ </gr-button>
+ </gr-tooltip-content>
</template>
</section>
<section
@@ -113,24 +116,27 @@
items="[[_topLevelSecondaryActions]]"
as="action"
>
- <gr-button
- link=""
+ <gr-tooltip-content
title$="[[action.title]]"
has-tooltip="[[_computeHasTooltip(action.title)]]"
position-below="true"
- data-action-key$="[[action.__key]]"
- class$="[[action.__key]]"
- data-action-type$="[[action.__type]]"
- data-label$="[[action.label]]"
- disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
- on-click="_handleActionTap"
>
- <iron-icon
- class$="[[_computeHasIcon(action)]]"
- icon$="gr-icons:[[action.icon]]"
- ></iron-icon>
- [[action.label]]
- </gr-button>
+ <gr-button
+ link=""
+ data-action-key$="[[action.__key]]"
+ class$="[[action.__key]]"
+ data-action-type$="[[action.__type]]"
+ data-label$="[[action.label]]"
+ disabled$="[[_calculateDisabled(action, _hasKnownChainState)]]"
+ on-click="_handleActionTap"
+ >
+ <iron-icon
+ class$="[[_computeHasIcon(action)]]"
+ icon$="gr-icons:[[action.icon]]"
+ ></iron-icon>
+ [[action.label]]
+ </gr-button>
+ </gr-tooltip-content>
</template>
</section>
<gr-button hidden$="[[!_loading]]" disabled=""
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
index 906300f..26e2fb4 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.ts
@@ -54,7 +54,7 @@
} from '../../../types/common';
import {ActionType} from '../../../api/change-actions';
import {tap} from '@polymer/iron-test-helpers/mock-interactions';
-import {SinonFakeTimers} from 'sinon/pkg/sinon-esm';
+import {SinonFakeTimers} from 'sinon';
import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea';
import {GrButton} from '../../shared/gr-button/gr-button';
import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
@@ -1094,7 +1094,7 @@
);
tap(abandonButton);
- assert.isUndefined(element.$.confirmAbandonDialog.message);
+ assert.equal(element.$.confirmAbandonDialog.message, '');
});
test('works', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index e06f664..08ad2bd 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -17,7 +17,6 @@
import '../../../styles/shared-styles';
import '../../../styles/gr-change-metadata-shared-styles';
import '../../../styles/gr-change-view-integration-shared-styles';
-import '../../../styles/gr-voting-styles';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../plugins/gr-external-style/gr-external-style';
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 c080345..a37daaa 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
@@ -134,9 +134,9 @@
<span class="title">Submitted</span>
<span class="value">
<gr-date-formatter
- has-tooltip=""
+ withTooltip
date-str="[[change.submitted]]"
- show-yesterday=""
+ showYesterday=""
></gr-date-formatter>
</span>
</section>
@@ -154,9 +154,9 @@
</span>
<span class="value">
<gr-date-formatter
- has-tooltip=""
+ withTooltip
date-str="[[change.updated]]"
- show-yesterday=""
+ showYesterday
></gr-date-formatter>
</span>
</section>
@@ -354,8 +354,8 @@
></gr-commit-info>
<gr-tooltip-content
id="parentNotCurrentMessage"
- has-tooltip=""
- show-icon=""
+ has-tooltip
+ show-icon
title$="[[_notCurrentMessage]]"
></gr-tooltip-content>
</li>
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 cb4c9a4..422c91b 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
@@ -57,7 +57,7 @@
LabelValueToDescriptionMap,
Hashtag,
} from '../../../types/common';
-import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonStubbedMember} from 'sinon';
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';
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 6a31c0a..414784c 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
@@ -17,7 +17,6 @@
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-icons/gr-icons';
-import '../../shared/gr-label/gr-label';
import '../../shared/gr-label-info/gr-label-info';
import '../../shared/gr-limited-text/gr-limited-text';
import {PolymerElement} from '@polymer/polymer/polymer-element';
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 97d8a37..831a309 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
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {css, customElement, property} from 'lit-element';
-import {GrLitElement} from '../../lit/gr-lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
+import {subscribe} from '../../lit/subscription-controller';
import {sharedStyles} from '../../../styles/shared-styles';
import {appContext} from '../../../services/app-context';
import {
@@ -24,11 +24,13 @@
aPluginHasRegistered$,
CheckResult,
CheckRun,
- errorMessageLatest$,
+ ErrorMessages,
+ errorMessagesLatest$,
loginCallbackLatest$,
- someProvidersAreLoadingLatest$,
+ someProvidersAreLoadingFirstTime$,
+ topLevelActionsLatest$,
} from '../../../services/checks/checks-model';
-import {Category, RunStatus} from '../../../api/checks';
+import {Action, Category, Link, RunStatus} from '../../../api/checks';
import {fireShowPrimaryTab} from '../../../utils/event-util';
import '../../shared/gr-avatar/gr-avatar';
import {
@@ -60,6 +62,8 @@
import {ChecksTabState, CommentTabState} from '../../../types/events';
import {spinnerStyles} from '../../../styles/gr-spinner-styles';
import {modifierPressed} from '../../../utils/dom-util';
+import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
+import {fontStyles} from '../../../styles/gr-font-styles';
export enum SummaryChipStyles {
INFO = 'info',
@@ -78,7 +82,7 @@
}
@customElement('gr-summary-chip')
-export class GrSummaryChip extends GrLitElement {
+export class GrSummaryChip extends LitElement {
@property()
icon = '';
@@ -93,6 +97,7 @@
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
.summaryChip {
color: var(--chip-color);
@@ -104,6 +109,10 @@
border-radius: 12px;
border: 1px solid gray;
vertical-align: top;
+ /* centered position of 20px chips in 24px line-height inline flow */
+ vertical-align: top;
+ position: relative;
+ top: 2px;
}
iron-icon {
width: var(--line-height-small);
@@ -164,19 +173,25 @@
}
@customElement('gr-checks-chip')
-export class GrChecksChip extends GrLitElement {
+export class GrChecksChip extends LitElement {
@property()
statusOrCategory?: Category | RunStatus;
@property()
text = '';
+ @property()
+ links: Link[] = [];
+
static override get styles() {
return [
+ fontStyles,
sharedStyles,
css`
:host {
display: inline-block;
+ position: relative;
+ white-space: nowrap;
}
.checksChip {
color: var(--chip-color);
@@ -187,7 +202,21 @@
var(--spacing-s);
border-radius: 12px;
border: 1px solid gray;
+ /* centered position of 20px chips in 24px line-height inline flow */
vertical-align: top;
+ position: relative;
+ top: 2px;
+ }
+ .checksChip.hoverFullLength {
+ position: absolute;
+ z-index: 1;
+ display: none;
+ }
+ .checksChip.hoverFullLength .text {
+ max-width: 400px;
+ }
+ :host(:hover) .checksChip.hoverFullLength {
+ display: inline-block;
}
.checksChip .text {
display: inline-block;
@@ -292,20 +321,51 @@
ariaLabel = `${this.text} ${label} ${type}${plural}`;
}
const chipClass = `checksChip font-small ${icon}`;
+ const chipClassFullLength = `${chipClass} hoverFullLength`;
const grIcon = `gr-icons:${icon}`;
+ // 15 is roughly the number of chars for the chip exceeding its 120px width.
return html`
- <div
- class="${chipClass}"
- role="link"
- tabindex="0"
- aria-label="${ariaLabel}"
- >
- <iron-icon icon="${grIcon}"></iron-icon>
+ ${this.text.length > 15
+ ? html` ${this.renderChip(chipClassFullLength, ariaLabel, grIcon)}`
+ : ''}
+ ${this.renderChip(chipClass, ariaLabel, grIcon)}
+ `;
+ }
+
+ private renderChip(clazz: string, ariaLabel: string, icon: string) {
+ return html`
+ <div class="${clazz}" role="link" tabindex="0" aria-label="${ariaLabel}">
+ <iron-icon icon="${icon}"></iron-icon>
<div class="text">${this.text}</div>
- <slot></slot>
+ ${this.renderLinks()}
</div>
`;
}
+
+ private renderLinks() {
+ return this.links.map(
+ link => html`
+ <a
+ href="${link.url}"
+ target="_blank"
+ @click="${this.onLinkClick}"
+ @keydown="${this.onLinkKeyDown}"
+ aria-label="Link to check details"
+ ><iron-icon class="launch" icon="gr-icons:launch"></iron-icon
+ ></a>
+ `
+ );
+ }
+
+ private onLinkKeyDown(e: KeyboardEvent) {
+ // Prevents onChipKeyDown() from reacting to <a> link keyboard events.
+ e.stopPropagation();
+ }
+
+ private onLinkClick(e: MouseEvent) {
+ // Prevents onChipClick() from reacting to <a> link clicks.
+ e.stopPropagation();
+ }
}
/** What is the maximum number of detailed checks chips? */
@@ -315,7 +375,7 @@
DETAILS_QUOTA.set(RunStatus.RUNNING, 2);
@customElement('gr-change-summary')
-export class GrChangeSummary extends GrLitElement {
+export class GrChangeSummary extends LitElement {
@property({type: Object})
changeComments?: ChangeComments;
@@ -335,20 +395,30 @@
someProvidersAreLoading = false;
@property()
- errorMessage?: string;
+ errorMessages: ErrorMessages = {};
@property()
loginCallback?: () => void;
+ @property()
+ actions: Action[] = [];
+
private showAllChips = new Map<RunStatus | Category, boolean>();
+ private checksService = appContext.checksService;
+
constructor() {
super();
- this.subscribe('runs', allRunsLatestPatchsetLatestAttempt$);
- this.subscribe('showChecksSummary', aPluginHasRegistered$);
- this.subscribe('someProvidersAreLoading', someProvidersAreLoadingLatest$);
- this.subscribe('errorMessage', errorMessageLatest$);
- this.subscribe('loginCallback', loginCallbackLatest$);
+ subscribe(this, allRunsLatestPatchsetLatestAttempt$, x => (this.runs = x));
+ subscribe(this, aPluginHasRegistered$, x => (this.showChecksSummary = x));
+ subscribe(
+ this,
+ someProvidersAreLoadingFirstTime$,
+ x => (this.someProvidersAreLoading = x)
+ );
+ subscribe(this, errorMessagesLatest$, x => (this.errorMessages = x));
+ subscribe(this, loginCallbackLatest$, x => (this.loginCallback = x));
+ subscribe(this, topLevelActionsLatest$, x => (this.actions = x));
}
static override get styles() {
@@ -372,7 +442,8 @@
.login {
display: flex;
color: var(--primary-text-color);
- padding: var(--spacing-s);
+ padding: 0 var(--spacing-s);
+ margin: var(--spacing-xs) 0;
width: 490px;
}
div.error {
@@ -383,9 +454,17 @@
width: 16px;
height: 16px;
position: relative;
- top: 2px;
+ top: 4px;
margin-right: var(--spacing-s);
}
+ div.error .right {
+ overflow: hidden;
+ }
+ div.error .right .message {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
.login {
justify-content: space-between;
background: var(--info-background);
@@ -398,8 +477,8 @@
}
td.key {
padding-right: var(--spacing-l);
- padding-bottom: var(--spacing-m);
- vertical-align: top;
+ padding-bottom: var(--spacing-s);
+ line-height: calc(var(--line-height-normal) + var(--spacing-s));
}
td.value {
padding-right: var(--spacing-l);
@@ -428,27 +507,90 @@
/* Making up for the 2px reduced height above. */
top: 1px;
}
+ .actions {
+ margin-left: calc(0px - var(--spacing-m));
+ line-height: var(--line-height-normal);
+ }
+ .actions gr-checks-action,
+ .actions gr-dropdown {
+ vertical-align: top;
+ --padding: 0 var(--spacing-m);
+ }
+ .actions #moreMessage {
+ display: none;
+ }
`,
];
}
- renderChecksError() {
- if (!this.errorMessage) return;
+ private renderActions() {
+ const actions = this.actions ?? [];
+ const summaryActions = actions.filter(a => a.summary).slice(0, 2);
+ if (summaryActions.length === 0) return;
+ const topActions = summaryActions.slice(0, 2);
+ const overflowActions = summaryActions.slice(2).map(action => {
+ return {...action, id: action.name};
+ });
+ const disabledActionIds = overflowActions
+ .filter(action => action.disabled)
+ .map(action => action.id);
+
return html`
- <div class="error zeroState">
- <div class="left">
- <iron-icon icon="gr-icons:error"></iron-icon>
- </div>
- <div class="right">
- <div>Error while fetching check results</div>
- <div>${this.errorMessage}</div>
- </div>
+ <div class="actions">
+ ${topActions.map(this.renderAction)}
+ ${this.renderOverflow(overflowActions, disabledActionIds)}
</div>
`;
}
+ private renderAction(action?: Action) {
+ if (!action) return;
+ return html`<gr-checks-action .action="${action}"></gr-checks-action>`;
+ }
+
+ private handleAction(e: CustomEvent<Action>) {
+ this.checksService.triggerAction(e.detail);
+ }
+
+ private renderOverflow(items: DropdownLink[], disabledIds: string[] = []) {
+ if (items.length === 0) return;
+ return html`
+ <gr-dropdown
+ id="moreActions"
+ link=""
+ vertical-offset="32"
+ horizontal-align="right"
+ @tap-item="${this.handleAction}"
+ .items="${items}"
+ .disabledIds="${disabledIds}"
+ >
+ <iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
+ </iron-icon>
+ <span id="moreMessage">More</span>
+ </gr-dropdown>
+ `;
+ }
+
+ renderErrorMessages() {
+ return Object.entries(this.errorMessages).map(
+ ([plugin, message]) =>
+ html`
+ <div class="error zeroState">
+ <div class="left">
+ <iron-icon icon="gr-icons:error"></iron-icon>
+ </div>
+ <div class="right">
+ <div class="message" title="${message}">
+ Error while fetching results for ${plugin}: ${message}
+ </div>
+ </div>
+ </div>
+ `
+ );
+ }
+
renderChecksLogin() {
- if (this.errorMessage || !this.loginCallback) return;
+ if (!this.loginCallback) return;
return html`
<div class="login">
<div class="left">
@@ -466,14 +608,14 @@
}
renderChecksZeroState() {
- if (this.errorMessage || this.loginCallback) return;
+ if (Object.keys(this.errorMessages).length > 0) return;
+ if (this.loginCallback) return;
if (this.runs.some(isRunningOrHasCompleted)) return;
const msg = this.someProvidersAreLoading ? 'Loading results' : 'No results';
return html`<span role="status" class="loading zeroState">${msg}</span>`;
}
renderChecksChipForCategory(category: Category) {
- if (this.errorMessage || this.loginCallback) return;
const runs = this.runs.filter(run => {
if (hasResultsOf(run, category)) return true;
return category === Category.SUCCESS && hasCompletedWithoutResults(run);
@@ -486,7 +628,6 @@
}
renderChecksChipRunning() {
- if (this.errorMessage || this.loginCallback) return;
const runs = this.runs.filter(isRunning);
return this.renderChecksChipsExpanded(runs, RunStatus.RUNNING, () => []);
}
@@ -563,21 +704,10 @@
return html`<gr-checks-chip
.statusOrCategory="${statusOrCategory}"
.text="${text}"
+ .links="${links}"
@click="${handler}"
@keydown="${(e: KeyboardEvent) => handleSpaceOrEnter(e, handler)}"
- >${links.map(
- link => html`
- <a
- href="${link.url}"
- target="_blank"
- @click="${this.onLinkClick}"
- @keydown="${this.onLinkKeyDown}"
- aria-label="Link to check details"
- ><iron-icon class="launch" icon="gr-icons:launch"></iron-icon
- ></a>
- `
- )}
- </gr-checks-chip>`;
+ ></gr-checks-chip>`;
}
private onChipClick(state: ChecksTabState) {
@@ -586,16 +716,6 @@
});
}
- private onLinkKeyDown(e: KeyboardEvent) {
- // Prevents onConChipKeyDown() from reacting to <a> link keyboard events.
- e.stopPropagation();
- }
-
- private onLinkClick(e: MouseEvent) {
- // Prevents onChipClick() from reacting to <a> link clicks.
- e.stopPropagation();
- }
-
override render() {
const commentThreads =
this.commentThreads?.filter(t => !isRobotThread(t) || hasHumanReply(t)) ??
@@ -616,7 +736,6 @@
<td class="key">Checks</td>
<td class="value">
<div class="checksSummary">
- ${this.renderChecksError()}${this.renderChecksLogin()}
${this.renderChecksZeroState()}${this.renderChecksChipForCategory(
Category.ERROR
)}${this.renderChecksChipForCategory(
@@ -632,6 +751,7 @@
class="loadingSpin"
?hidden="${!this.someProvidersAreLoading}"
></span>
+ ${this.renderErrorMessages()}${this.renderChecksLogin()}${this.renderActions()}
</div>
</td>
</tr>
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 5ec35c4..3396e13 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
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '@polymer/paper-tabs/paper-tabs';
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../../diff/gr-comment-api/gr-comment-api';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
@@ -23,7 +24,6 @@
import '../../shared/gr-button/gr-button';
import '../../shared/gr-change-star/gr-change-star';
import '../../shared/gr-change-status/gr-change-status';
-import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../shared/gr-editable-content/gr-editable-content';
import '../../shared/gr-linked-text/gr-linked-text';
import '../../shared/gr-overlay/gr-overlay';
@@ -51,7 +51,7 @@
} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {GrEditConstants} from '../../edit/gr-edit-constants';
import {pluralize} from '../../../utils/string-util';
-import {windowLocationReload} from '../../../utils/dom-util';
+import {windowLocationReload, querySelectorAll} from '../../../utils/dom-util';
import {
GeneratedWebLink,
GerritNav,
@@ -84,6 +84,7 @@
isCc,
isOwner,
isReviewer,
+ isInvolved,
} from '../../../utils/change-util';
import {EventType as PluginEventType} from '../../../api/plugin';
import {customElement, observe, property} from '@polymer/decorators';
@@ -188,6 +189,11 @@
changeComments$,
drafts$,
} from '../../../services/comments/comments-model';
+import {
+ hasAttention,
+ getAddedByReason,
+ getRemovedByReason,
+} from '../../../utils/attention-set-util';
const MIN_LINES_FOR_COMMIT_COLLAPSE = 18;
@@ -200,7 +206,7 @@
const TRAILING_WHITESPACE_REGEX = /[ \t]+$/gm;
-const MSG_PREFIX = '#message-';
+const PREFIX = '#message-';
const ReloadToastMessage = {
NEWER_REVISION: 'A newer patch set has been uploaded',
@@ -239,8 +245,11 @@
export type ChangeViewPatchRange = Partial<PatchRange>;
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-change-view')
-export class GrChangeView extends KeyboardShortcutMixin(PolymerElement) {
+export class GrChangeView extends base {
static get template() {
return htmlTemplate;
}
@@ -575,6 +584,8 @@
[Shortcut.DIFF_BASE_AGAINST_LEFT]: '_handleDiffBaseAgainstLeft',
[Shortcut.DIFF_RIGHT_AGAINST_LATEST]: '_handleDiffRightAgainstLatest',
[Shortcut.DIFF_BASE_AGAINST_LATEST]: '_handleDiffBaseAgainstLatest',
+ [Shortcut.OPEN_SUBMIT_DIALOG]: '_handleOpenSubmitDialog',
+ [Shortcut.TOGGLE_ATTENTION_SET]: '_handleToggleAttentionSet',
};
}
@@ -1168,6 +1179,9 @@
_paramsChanged(value: AppElementChangeViewParams) {
if (value.view !== GerritView.CHANGE) {
this._initialLoadComplete = false;
+ querySelectorAll(this, 'gr-overlay').forEach(overlay =>
+ (overlay as GrOverlay).close()
+ );
return;
}
@@ -1182,10 +1196,12 @@
this.restApiService.setInProjectLookup(value.changeNum, value.project);
}
+ if (value.basePatchNum === undefined)
+ value.basePatchNum = ParentPatchSetNum;
+
const patchChanged =
this._patchRange &&
value.patchNum !== undefined &&
- value.basePatchNum !== undefined &&
(this._patchRange.patchNum !== value.patchNum ||
this._patchRange.basePatchNum !== value.basePatchNum);
@@ -1196,7 +1212,7 @@
const patchRange: ChangeViewPatchRange = {
patchNum: value.patchNum,
- basePatchNum: value.basePatchNum || ParentPatchSetNum,
+ basePatchNum: value.basePatchNum,
};
this.$.fileList.collapseAllDiffs();
@@ -1311,7 +1327,7 @@
assertIsDefined(this._change, '_change');
if (!this._patchRange)
throw new Error('missing required _patchRange property');
- const hash = MSG_PREFIX + e.detail.id;
+ const hash = PREFIX + e.detail.id;
const url = GerritNav.getUrlForChange(
this._change,
this._patchRange.patchNum,
@@ -1323,8 +1339,8 @@
}
_maybeScrollToMessage(hash: string) {
- if (hash.startsWith(MSG_PREFIX) && this.messagesList) {
- this.messagesList.scrollToMessage(hash.substr(MSG_PREFIX.length));
+ if (hash.startsWith(PREFIX) && this.messagesList) {
+ this.messagesList.scrollToMessage(hash.substr(PREFIX.length));
}
}
@@ -1508,6 +1524,57 @@
this.$.metadata.editTopic();
}
+ _handleOpenSubmitDialog(e: CustomKeyboardEvent) {
+ if (this.shouldSuppressKeyboardShortcut(e) || !this._submitEnabled) {
+ return;
+ }
+
+ e.preventDefault();
+ this.$.actions.showSubmitDialog();
+ }
+
+ _handleToggleAttentionSet(e: CustomKeyboardEvent) {
+ if (this.shouldSuppressKeyboardShortcut(e)) {
+ return;
+ }
+ if (!this._change || !this._account?._account_id) return;
+ if (!this._loggedIn || !isInvolved(this._change, this._account)) return;
+ if (!this._change.attention_set) this._change.attention_set = {};
+ if (hasAttention(this._account, this._change)) {
+ const reason = getRemovedByReason(this._account, this._serverConfig);
+ if (this._change.attention_set)
+ delete this._change.attention_set[this._account._account_id];
+ fireAlert(this, 'Removing you from the attention set ...');
+ this.restApiService
+ .removeFromAttentionSet(
+ this._change._number,
+ this._account._account_id,
+ reason
+ )
+ .then(() => {
+ fireEvent(this, 'hide-alert');
+ });
+ } else {
+ const reason = getAddedByReason(this._account, this._serverConfig);
+ fireAlert(this, 'Adding you to the attention set ...');
+ this._change.attention_set[this._account._account_id!] = {
+ account: this._account,
+ reason,
+ reason_account: this._account,
+ };
+ this.restApiService
+ .addToAttentionSet(
+ this._change._number,
+ this._account._account_id,
+ reason
+ )
+ .then(() => {
+ fireEvent(this, 'hide-alert');
+ });
+ }
+ this._change = {...this._change};
+ }
+
_handleDiffAgainstBase(e: CustomKeyboardEvent) {
if (this.shouldSuppressKeyboardShortcut(e)) {
return;
@@ -1811,8 +1878,9 @@
this.restApiService.getChange(changeId)
)
).then(changes => {
+ // if a change is deleted then getChanges returns null for that changeId
changes = changes.filter(
- change => change?.status !== ChangeStatus.ABANDONED
+ change => change && change.status !== ChangeStatus.ABANDONED
);
if (!changes.length) return;
const submittedRevert = changes.find(
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 94d3117..d57aca8 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
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
.container:not(.loading) {
background-color: var(--background-color-tertiary);
@@ -299,7 +302,7 @@
.show-robot-comments {
margin: var(--spacing-m);
}
- .patchInfo gr-thread-list {
+ .patchInfo gr-thread-list::part(threads) {
padding: var(--spacing-l);
}
</style>
@@ -476,7 +479,7 @@
class="commentThreads"
>
<gr-tooltip-content
- has-tooltip=""
+ has-tooltip
title$="[[_computeTotalCommentCounts(_change.unresolved_comment_count, _changeComments)]]"
>
<span>Comments</span></gr-tooltip-content
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 5508ee0..6668e15 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
@@ -36,6 +36,7 @@
import 'lodash/lodash';
import {
+ mockPromise,
stubRestApi,
TestKeyboardShortcutBinder,
} from '../../../test/test-utils';
@@ -58,6 +59,7 @@
createAccountWithIdNameAndEmail,
createChangeViewChange,
createRelatedChangeAndCommitInfo,
+ createAccountDetailWithId,
} from '../../../test/test-data-generators';
import {ChangeViewPatchRange, GrChangeView} from './gr-change-view';
import {
@@ -89,7 +91,7 @@
} from '@polymer/iron-test-helpers/mock-interactions';
import {GrEditControls} from '../../edit/gr-edit-controls/gr-edit-controls';
import {AppElementChangeViewParams} from '../../gr-app-types';
-import {SinonFakeTimers, SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonFakeTimers, SinonStubbedMember} from 'sinon';
import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
import {CustomKeyboardEvent} from '../../../types/events';
import {CommentThread, UIRobot} from '../../../utils/comment-util';
@@ -365,7 +367,9 @@
},
})
);
- stubRestApi('getAccount').returns(Promise.resolve(undefined));
+ stubRestApi('getAccount').returns(
+ Promise.resolve(createAccountDetailWithId(5))
+ );
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
@@ -389,10 +393,8 @@
);
});
- teardown(done => {
- flush(() => {
- done();
- });
+ teardown(async () => {
+ await flush();
});
test('_handleMessageAnchorTap', () => {
@@ -446,7 +448,7 @@
const args = navigateToChangeStub.getCall(0).args;
assert.equal(args[0], element._change);
assert.equal(args[1], 10 as PatchSetNum);
- assert.equal(args[2], 1 as PatchSetNum);
+ assert.equal(args[2], 1 as BasePatchSetNum);
});
test('_handleDiffBaseAgainstLeft', () => {
@@ -484,7 +486,7 @@
assert(navigateToChangeStub.called);
const args = navigateToChangeStub.getCall(0).args;
assert.equal(args[1], 10 as PatchSetNum);
- assert.equal(args[2], 3 as PatchSetNum);
+ assert.equal(args[2], 3 as BasePatchSetNum);
});
test('_handleDiffBaseAgainstLatest', () => {
@@ -506,12 +508,45 @@
assert.isNotOk(args[2]);
});
+ test('toggle attention set status', async () => {
+ element._change = {
+ ...createChangeViewChange(),
+ revisions: createRevisions(10),
+ };
+ const addToAttentionSetStub = stubRestApi('addToAttentionSet').returns(
+ Promise.resolve(new Response())
+ );
+
+ const removeFromAttentionSetStub = stubRestApi(
+ 'removeFromAttentionSet'
+ ).returns(Promise.resolve(new Response()));
+ element._patchRange = {
+ basePatchNum: 1 as BasePatchSetNum,
+ patchNum: 3 as RevisionPatchSetNum,
+ };
+ sinon.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
+
+ assert.isNotOk(element._change.attention_set);
+ await element._getLoggedIn();
+ await element.restApiService.getAccount();
+ element._handleToggleAttentionSet(
+ new CustomEvent('') as CustomKeyboardEvent
+ );
+ assert.isTrue(addToAttentionSetStub.called);
+ assert.isFalse(removeFromAttentionSetStub.called);
+
+ element._handleToggleAttentionSet(
+ new CustomEvent('') as CustomKeyboardEvent
+ );
+ assert.isTrue(removeFromAttentionSetStub.called);
+ });
+
suite('plugins adding to file tab', () => {
- setup(done => {
+ setup(async () => {
element._changeNum = TEST_NUMERIC_CHANGE_ID;
// Resolving it here instead of during setup() as other tests depend
// on flush() not being called during setup.
- flush(() => done());
+ await flush();
});
test('plugin added tab shows up as a dynamic endpoint', () => {
@@ -527,19 +562,17 @@
assert.equal(paperTabs[2].dataset.name, 'change-view-tab-header-url');
});
- test('_setActivePrimaryTab switched tab correctly', done => {
+ test('_setActivePrimaryTab switched tab correctly', async () => {
element._setActivePrimaryTab(
new CustomEvent('', {
detail: {tab: 'change-view-tab-header-url'},
})
);
- flush(() => {
- assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
- done();
- });
+ await flush();
+ assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
});
- test('show-primary-tab switched primary tab correctly', done => {
+ test('show-primary-tab switched primary tab correctly', async () => {
element.dispatchEvent(
new CustomEvent('show-primary-tab', {
composed: true,
@@ -549,13 +582,11 @@
},
})
);
- flush(() => {
- assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
- done();
- });
+ await flush();
+ assert.equal(element._activeTabs[0], 'change-view-tab-header-url');
});
- test('param change should switch primary tab correctly', done => {
+ test('param change should switch primary tab correctly', async () => {
assert.equal(element._activeTabs[0], PrimaryTab.FILES);
const queryMap = new Map<string, string>();
queryMap.set('tab', PrimaryTab.FINDINGS);
@@ -565,13 +596,11 @@
...element.params,
queryMap,
};
- flush(() => {
- assert.equal(element._activeTabs[0], PrimaryTab.FINDINGS);
- done();
- });
+ await flush();
+ assert.equal(element._activeTabs[0], PrimaryTab.FINDINGS);
});
- test('invalid param change should not switch primary tab', done => {
+ test('invalid param change should not switch primary tab', async () => {
assert.equal(element._activeTabs[0], PrimaryTab.FILES);
const queryMap = new Map<string, string>();
queryMap.set('tab', 'random');
@@ -581,22 +610,18 @@
...element.params,
queryMap,
};
- flush(() => {
- assert.equal(element._activeTabs[0], PrimaryTab.FILES);
- done();
- });
+ await flush();
+ assert.equal(element._activeTabs[0], PrimaryTab.FILES);
});
- test('switching tab sets _selectedTabPluginEndpoint', done => {
+ test('switching tab sets _selectedTabPluginEndpoint', async () => {
const paperTabs = element.shadowRoot!.querySelector('#primaryTabs')!;
tap(paperTabs.querySelectorAll('paper-tab')[2]);
- flush(() => {
- assert.equal(
- element._selectedTabPluginEndpoint,
- 'change-view-tab-content-url'
- );
- done();
- });
+ await flush();
+ assert.equal(
+ element._selectedTabPluginEndpoint,
+ 'change-view-tab-content-url'
+ );
});
});
@@ -653,28 +678,24 @@
);
});
- test('A fires an error event when not logged in', done => {
+ test('A fires an error event when not logged in', async () => {
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
const loggedInErrorSpy = sinon.spy();
element.addEventListener('show-auth-required', loggedInErrorSpy);
pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isFalse(element.$.replyOverlay.opened);
- assert.isTrue(loggedInErrorSpy.called);
- done();
- });
+ await flush();
+ assert.isFalse(element.$.replyOverlay.opened);
+ assert.isTrue(loggedInErrorSpy.called);
});
- test('shift A does not open reply overlay', done => {
+ test('shift A does not open reply overlay', async () => {
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
pressAndReleaseKeyOn(element, 65, 'shift', 'a');
- flush(() => {
- assert.isFalse(element.$.replyOverlay.opened);
- done();
- });
+ await flush();
+ assert.isFalse(element.$.replyOverlay.opened);
});
- test('A toggles overlay when logged in', done => {
+ test('A toggles overlay when logged in', async () => {
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
element._change = {
...createChangeViewChange(),
@@ -695,19 +716,17 @@
const openSpy = sinon.spy(element, '_openReplyDialog');
pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isTrue(element.$.replyOverlay.opened);
- element.$.replyOverlay.close();
- assert.isFalse(element.$.replyOverlay.opened);
- assert(
- openSpy.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.ANY
- ),
- '_openReplyDialog should have been passed ANY'
- );
- assert.equal(openSpy.callCount, 1);
- done();
- });
+ await flush();
+ assert.isTrue(element.$.replyOverlay.opened);
+ element.$.replyOverlay.close();
+ assert.isFalse(element.$.replyOverlay.opened);
+ assert(
+ openSpy.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.ANY
+ ),
+ '_openReplyDialog should have been passed ANY'
+ );
+ assert.equal(openSpy.callCount, 1);
});
test('fullscreen-overlay-opened hides content', () => {
@@ -785,28 +804,24 @@
assert.isTrue(handleCollapse.called);
});
- test('X should expand all messages', done => {
- flush(() => {
- const handleExpand = sinon.stub(
- element.messagesList!,
- 'handleExpandCollapse'
- );
- pressAndReleaseKeyOn(element, 88, null, 'x');
- assert(handleExpand.calledWith(true));
- done();
- });
+ test('X should expand all messages', async () => {
+ await flush();
+ const handleExpand = sinon.stub(
+ element.messagesList!,
+ 'handleExpandCollapse'
+ );
+ pressAndReleaseKeyOn(element, 88, null, 'x');
+ assert(handleExpand.calledWith(true));
});
- test('Z should collapse all messages', done => {
- flush(() => {
- const handleExpand = sinon.stub(
- element.messagesList!,
- 'handleExpandCollapse'
- );
- pressAndReleaseKeyOn(element, 90, null, 'z');
- assert(handleExpand.calledWith(false));
- done();
- });
+ test('Z should collapse all messages', async () => {
+ await flush();
+ const handleExpand = sinon.stub(
+ element.messagesList!,
+ 'handleExpandCollapse'
+ );
+ pressAndReleaseKeyOn(element, 90, null, 'z');
+ assert(handleExpand.calledWith(false));
});
test('d should open download overlay', () => {
@@ -946,12 +961,10 @@
);
});
- test('changing patchsets resets robot comments', done => {
+ test('changing patchsets resets robot comments', async () => {
element.set('_change.current_revision', 'rev3');
- flush(() => {
- assert.equal(element._robotCommentThreads!.length, 1);
- done();
- });
+ await flush();
+ assert.equal(element._robotCommentThreads!.length, 1);
});
test('Show more button is hidden', () => {
@@ -959,15 +972,13 @@
});
suite('robot comments show more button', () => {
- setup(done => {
+ setup(async () => {
const arr = [];
for (let i = 0; i <= 30; i++) {
arr.push(...THREADS);
}
element._commentThreads = arr;
- flush(() => {
- done();
- });
+ await flush();
});
test('Show more button is rendered', () => {
@@ -978,12 +989,10 @@
);
});
- test('Clicking show more button renders all comments', done => {
+ test('Clicking show more button renders all comments', async () => {
tap(element.shadowRoot!.querySelector('.show-robot-comments')!);
- flush(() => {
- assert.equal(element._robotCommentThreads!.length, 62);
- done();
- });
+ await flush();
+ assert.equal(element._robotCommentThreads!.length, 62);
});
});
});
@@ -1005,14 +1014,12 @@
assert.isTrue(openDialogStub.called);
});
- test('fetches the server config on attached', done => {
- flush(() => {
- assert.equal(
- element._serverConfig!.user.anonymous_coward_name,
- 'test coward name'
- );
- done();
- });
+ test('fetches the server config on attached', async () => {
+ await flush();
+ assert.equal(
+ element._serverConfig!.user.anonymous_coward_name,
+ 'test coward name'
+ );
});
test('_changeStatuses', () => {
@@ -1047,7 +1054,7 @@
});
suite('ChangeStatus revert', () => {
- test('do not show any chip if no revert created', done => {
+ test('do not show any chip if no revert created', async () => {
const change = {
...createChange(),
messages: createChangeMessages(2),
@@ -1066,20 +1073,18 @@
element._change = change;
element._mergeable = true;
element._submitEnabled = true;
- flush();
+ await flush();
element.computeRevertSubmitted(element._change);
- flush(() => {
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
- );
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
- );
- done();
- });
+ await flush();
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
+ );
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
+ );
});
- test('do not show any chip if all reverts are abandoned', done => {
+ test('do not show any chip if all reverts are abandoned', async () => {
const change = {
...createChange(),
messages: createChangeMessages(2),
@@ -1106,20 +1111,18 @@
element._change = change;
element._mergeable = true;
element._submitEnabled = true;
- flush();
+ await flush();
element.computeRevertSubmitted(element._change);
- flush(() => {
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
- );
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
- );
- done();
- });
+ await flush();
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
+ );
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
+ );
});
- test('show revert created if no revert is merged', done => {
+ test('show revert created if no revert is merged', async () => {
const change = {
...createChange(),
messages: createChangeMessages(2),
@@ -1144,20 +1147,18 @@
element._change = change;
element._mergeable = true;
element._submitEnabled = true;
- flush();
+ await flush();
element.computeRevertSubmitted(element._change);
- flush(() => {
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
- );
- assert.isTrue(
- element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
- );
- done();
- });
+ await flush();
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
+ );
+ assert.isTrue(
+ element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
+ );
});
- test('show revert submitted if revert is merged', done => {
+ test('show revert submitted if revert is merged', async () => {
const change = {
...createChange(),
messages: createChangeMessages(2),
@@ -1179,17 +1180,15 @@
element._change = change;
element._mergeable = true;
element._submitEnabled = true;
- flush();
+ await flush();
element.computeRevertSubmitted(element._change);
- flush(() => {
- assert.isFalse(
- element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
- );
- assert.isTrue(
- element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
- );
- done();
- });
+ await flush();
+ assert.isFalse(
+ element._changeStatuses?.includes(ChangeStates.REVERT_CREATED)
+ );
+ assert.isTrue(
+ element._changeStatuses?.includes(ChangeStates.REVERT_SUBMITTED)
+ );
});
});
@@ -1343,17 +1342,15 @@
assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
});
- test('diffMode defaults to side by side without preferences', done => {
+ test('diffMode defaults to side by side without preferences', async () => {
stubRestApi('getPreferences').returns(Promise.resolve(createPreferences()));
// No user prefs or diff view mode set.
- element._setDiffViewMode()!.then(() => {
- assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
- done();
- });
+ await element._setDiffViewMode()!;
+ assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
});
- test('diffMode defaults to preference when not already set', done => {
+ test('diffMode defaults to preference when not already set', async () => {
stubRestApi('getPreferences').returns(
Promise.resolve({
...createPreferences(),
@@ -1361,13 +1358,11 @@
})
);
- element._setDiffViewMode()!.then(() => {
- assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
- done();
- });
+ await element._setDiffViewMode()!;
+ assert.equal(element.viewState.diffMode, DiffViewMode.UNIFIED);
});
- test('existing diffMode overrides preference', done => {
+ test('existing diffMode overrides preference', async () => {
element.viewState.diffMode = DiffViewMode.SIDE_BY_SIDE;
stubRestApi('getPreferences').returns(
Promise.resolve({
@@ -1375,10 +1370,8 @@
default_diff_view: DiffViewMode.UNIFIED,
})
);
- element._setDiffViewMode()!.then(() => {
- assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
- done();
- });
+ await element._setDiffViewMode()!;
+ assert.equal(element.viewState.diffMode, DiffViewMode.SIDE_BY_SIDE);
});
test('don’t reload entire page when patchRange changes', async () => {
@@ -1486,17 +1479,15 @@
assert.isTrue(recreateSpy.calledOnce);
});
- test('related changes are not updated after other action', done => {
+ test('related changes are not updated after other action', async () => {
sinon.stub(element, 'loadData').callsFake(() => Promise.resolve());
- flush();
+ await flush();
const relatedChanges = element.shadowRoot!.querySelector(
'#relatedChanges'
) as GrRelatedChangesList;
sinon.stub(relatedChanges, 'reload');
- element.loadData(true).then(() => {
- assert.isFalse(navigateToChangeStub.called);
- done();
- });
+ await element.loadData(true);
+ assert.isFalse(navigateToChangeStub.called);
});
test('_computeCopyTextForTitle', () => {
@@ -1578,7 +1569,7 @@
assert.equal(putStub.lastCall.args[1], '\n\n\n\n\n\n\n\n');
});
- test('topic is coalesced to null', done => {
+ test('topic is coalesced to null', async () => {
sinon.stub(element, '_changeChanged');
stubRestApi('getChangeDetail').returns(
Promise.resolve({
@@ -1589,13 +1580,11 @@
})
);
- element._getChangeDetail().then(() => {
- assert.isNull(element._change!.topic);
- done();
- });
+ await element._getChangeDetail();
+ assert.isNull(element._change!.topic);
});
- test('commit sha is populated from getChangeDetail', done => {
+ test('commit sha is populated from getChangeDetail', async () => {
sinon.stub(element, '_changeChanged');
stubRestApi('getChangeDetail').callsFake(() =>
Promise.resolve({
@@ -1606,10 +1595,8 @@
})
);
- element._getChangeDetail().then(() => {
- assert.equal('foo', element._commitInfo!.commit);
- done();
- });
+ await element._getChangeDetail();
+ assert.equal('foo', element._commitInfo!.commit);
});
test('edit is added to change', () => {
@@ -1693,43 +1680,39 @@
assert.equal(element._getBasePatchNum(_change2, _patchRange), 'PARENT');
});
- test('_openReplyDialog called with `ANY` when coming from tap event', done => {
- flush(() => {
- const openStub = sinon.stub(element, '_openReplyDialog');
- tap(element.$.replyBtn);
- assert(
- openStub.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.ANY
- ),
- '_openReplyDialog should have been passed ANY'
- );
- assert.equal(openStub.callCount, 1);
- done();
- });
+ test('_openReplyDialog called with `ANY` when coming from tap event', async () => {
+ await flush();
+ const openStub = sinon.stub(element, '_openReplyDialog');
+ tap(element.$.replyBtn);
+ assert(
+ openStub.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.ANY
+ ),
+ '_openReplyDialog should have been passed ANY'
+ );
+ assert.equal(openStub.callCount, 1);
});
test(
'_openReplyDialog called with `BODY` when coming from message reply' +
'event',
- done => {
- flush(() => {
- const openStub = sinon.stub(element, '_openReplyDialog');
- element.messagesList!.dispatchEvent(
- new CustomEvent('reply', {
- detail: {message: {message: 'text'}},
- composed: true,
- bubbles: true,
- })
- );
- assert(
- openStub.lastCall.calledWithExactly(
- element.$.replyDialog.FocusTarget.BODY
- ),
- '_openReplyDialog should have been passed BODY'
- );
- assert.equal(openStub.callCount, 1);
- done();
- });
+ async () => {
+ await flush();
+ const openStub = sinon.stub(element, '_openReplyDialog');
+ element.messagesList!.dispatchEvent(
+ new CustomEvent('reply', {
+ detail: {message: {message: 'text'}},
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert(
+ openStub.lastCall.calledWithExactly(
+ element.$.replyDialog.FocusTarget.BODY
+ ),
+ '_openReplyDialog should have been passed BODY'
+ );
+ assert.equal(openStub.callCount, 1);
}
);
@@ -1771,7 +1754,7 @@
assert.isNull(element._getUrlParameter('test'));
});
- test('revert dialog opened with revert param', done => {
+ test('revert dialog opened with revert param', async () => {
const awaitPluginsLoadedStub = sinon
.stub(getPluginLoader(), 'awaitPluginsLoaded')
.callsFake(() => Promise.resolve());
@@ -1797,10 +1780,15 @@
return param;
});
- sinon.stub(element.$.actions, 'showRevertDialog').callsFake(done);
+ const promise = mockPromise();
+
+ sinon
+ .stub(element.$.actions, 'showRevertDialog')
+ .callsFake(() => promise.resolve());
element._maybeShowRevertDialog();
assert.isTrue(awaitPluginsLoadedStub.called);
+ await promise;
});
suite('reply dialog tests', () => {
@@ -1823,7 +1811,7 @@
);
});
- test('show reply dialog on open-reply-dialog event', done => {
+ test('show reply dialog on open-reply-dialog event', async () => {
const openReplyDialogStub = sinon.stub(element, '_openReplyDialog');
element.dispatchEvent(
new CustomEvent('open-reply-dialog', {
@@ -1832,10 +1820,8 @@
detail: {},
})
);
- flush(() => {
- assert.isTrue(openReplyDialogStub.calledOnce);
- done();
- });
+ await flush();
+ assert.isTrue(openReplyDialogStub.calledOnce);
});
test('reply from comment adds quote text', () => {
@@ -1887,13 +1873,11 @@
});
});
- test('reply button is disabled until server config is loaded', done => {
+ test('reply button is disabled until server config is loaded', async () => {
assert.isTrue(element._replyDisabled);
// fetches the server config on attached
- flush(() => {
- assert.isFalse(element._replyDisabled);
- done();
- });
+ await flush();
+ assert.isFalse(element._replyDisabled);
});
test('header class computation', () => {
@@ -1901,19 +1885,17 @@
assert.equal(element._computeHeaderClass(true), 'header editMode');
});
- test('_maybeScrollToMessage', done => {
- flush(() => {
- const scrollStub = sinon.stub(element.messagesList!, 'scrollToMessage');
+ test('_maybeScrollToMessage', async () => {
+ await flush();
+ const scrollStub = sinon.stub(element.messagesList!, 'scrollToMessage');
- element._maybeScrollToMessage('');
- assert.isFalse(scrollStub.called);
- element._maybeScrollToMessage('message');
- assert.isFalse(scrollStub.called);
- element._maybeScrollToMessage('#message-TEST');
- assert.isTrue(scrollStub.called);
- assert.equal(scrollStub.lastCall.args[0], 'TEST');
- done();
- });
+ element._maybeScrollToMessage('');
+ assert.isFalse(scrollStub.called);
+ element._maybeScrollToMessage('message');
+ assert.isFalse(scrollStub.called);
+ element._maybeScrollToMessage('#message-TEST');
+ assert.isTrue(scrollStub.called);
+ assert.equal(scrollStub.lastCall.args[0], 'TEST');
});
test('topic update reloads related changes', () => {
@@ -2172,94 +2154,93 @@
};
});
- test('edit exists in revisions', done => {
+ test('edit exists in revisions', async () => {
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
assert.equal(args.length, 2);
assert.equal(args[1], EditPatchSetNum); // patchNum
- done();
+ promise.resolve();
});
element.set('_change.revisions.rev2', {
_number: EditPatchSetNum,
});
- flush();
+ await flush();
fireEdit();
+ await promise;
});
- test('no edit exists in revisions, non-latest patchset', done => {
+ test('no edit exists in revisions, non-latest patchset', async () => {
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
assert.equal(args.length, 4);
assert.equal(args[1], 1 as PatchSetNum); // patchNum
assert.equal(args[3], true); // opt_isEdit
- done();
+ promise.resolve();
});
element.set('_change.revisions.rev2', {_number: 2});
element._patchRange = {patchNum: 1 as RevisionPatchSetNum};
- flush();
+ await flush();
fireEdit();
+ await promise;
});
- test('no edit exists in revisions, latest patchset', done => {
+ test('no edit exists in revisions, latest patchset', async () => {
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
assert.equal(args.length, 4);
// No patch should be specified when patchNum == latest.
assert.isNotOk(args[1]); // patchNum
assert.equal(args[3], true); // opt_isEdit
- done();
+ promise.resolve();
});
element.set('_change.revisions.rev2', {_number: 2});
element._patchRange = {patchNum: 2 as RevisionPatchSetNum};
- flush();
+ await flush();
fireEdit();
+ await promise;
});
});
- test('_handleStopEditTap', done => {
+ test('_handleStopEditTap', async () => {
element._change = {
...createChangeViewChange(),
};
sinon.stub(element.$.metadata, '_computeLabelNames');
navigateToChangeStub.restore();
+ const promise = mockPromise();
sinon.stub(GerritNav, 'navigateToChange').callsFake((...args) => {
assert.equal(args.length, 2);
assert.equal(args[1], 1 as PatchSetNum); // patchNum
- done();
+ promise.resolve();
});
element._patchRange = {patchNum: 1 as RevisionPatchSetNum};
element.$.actions.dispatchEvent(
new CustomEvent('stop-edit-tap', {bubbles: false})
);
+ await promise;
});
suite('plugin endpoints', () => {
- test('endpoint params', done => {
+ test('endpoint params', async () => {
element._change = {...createChangeViewChange(), labels: {}};
element._selectedRevision = createRevision();
- let hookEl: HTMLElement;
- let plugin: PluginApi;
- pluginApi.install(
- p => {
- plugin = p;
- plugin
- .hook('change-view-integration')
- .getLastAttached()
- .then(el => (hookEl = el));
- },
- '0.1',
- 'http://some/plugins/url.js'
- );
- flush(() => {
- assert.strictEqual((hookEl as any).plugin, plugin);
- assert.strictEqual((hookEl as any).change, element._change);
- assert.strictEqual((hookEl as any).revision, element._selectedRevision);
- done();
- });
+ const promise = mockPromise();
+ pluginApi.install(promise.resolve, '0.1', 'http://some/plugins/url.js');
+ await flush();
+ const plugin: PluginApi = (await promise) as PluginApi;
+ const hookEl = await plugin
+ .hook('change-view-integration')
+ .getLastAttached();
+ assert.strictEqual((hookEl as any).plugin, plugin);
+ assert.strictEqual((hookEl as any).change, element._change);
+ assert.strictEqual((hookEl as any).revision, element._selectedRevision);
});
});
@@ -2328,7 +2309,7 @@
.returns(Promise.resolve([undefined, undefined, undefined]));
});
- test("don't report changeDisplayed on reply", done => {
+ test("don't report changeDisplayed on reply", async () => {
const changeDisplayStub = sinon.stub(
appContext.reportingService,
'changeDisplayed'
@@ -2338,11 +2319,9 @@
'changeFullyLoaded'
);
element._handleReplySent();
- flush(() => {
- assert.isFalse(changeDisplayStub.called);
- assert.isFalse(changeFullyLoadedStub.called);
- done();
- });
+ await flush();
+ assert.isFalse(changeDisplayStub.called);
+ assert.isFalse(changeFullyLoadedStub.called);
});
test('report changeDisplayed on _paramsChanged', async () => {
diff --git a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
index 796b35d..4326939 100644
--- a/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
+++ b/polygerrit-ui/app/elements/change/gr-commit-info/gr-commit-info.ts
@@ -19,8 +19,8 @@
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {ChangeInfo, CommitInfo, ServerInfo} from '../../../types/common';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -29,7 +29,7 @@
}
@customElement('gr-commit-info')
-export class GrCommitInfo extends GrLitElement {
+export class GrCommitInfo extends LitElement {
// TODO(TS): can not use `?` here as @computed require dependencies as
// not optional
@property({type: Object})
@@ -43,7 +43,7 @@
@property({type: Object})
serverConfig: ServerInfo | undefined;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -55,7 +55,7 @@
];
}
- render() {
+ override render() {
return html` <div class="container">
<a
target="_blank"
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
index 0954b7f..07da53f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog.ts
@@ -35,10 +35,11 @@
}
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-confirm-abandon-dialog')
-export class GrConfirmAbandonDialog extends KeyboardShortcutMixin(
- PolymerElement
-) {
+export class GrConfirmAbandonDialog extends base {
static get template() {
return htmlTemplate;
}
@@ -56,7 +57,7 @@
*/
@property({type: String})
- message?: string;
+ message = '';
get keyBindings() {
return {
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.js
deleted file mode 100644
index 14d16f5..0000000
--- a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 '../../../test/common-test-setup-karma.js';
-import './gr-confirm-abandon-dialog.js';
-
-const basicFixture = fixtureFromElement('gr-confirm-abandon-dialog');
-
-suite('gr-confirm-abandon-dialog tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('_handleConfirmTap', () => {
- const confirmHandler = sinon.stub();
- element.addEventListener('confirm', confirmHandler);
- sinon.spy(element, '_handleConfirmTap');
- sinon.spy(element, '_confirm');
- element.shadowRoot
- .querySelector('gr-dialog').dispatchEvent(
- new CustomEvent('confirm', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(confirmHandler.called);
- assert.isTrue(confirmHandler.calledOnce);
- assert.isTrue(element._handleConfirmTap.called);
- assert.isTrue(element._confirm.called);
- assert.isTrue(element._confirm.calledOnce);
- });
-
- test('_handleCancelTap', () => {
- const cancelHandler = sinon.stub();
- element.addEventListener('cancel', cancelHandler);
- sinon.spy(element, '_handleCancelTap');
- element.shadowRoot
- .querySelector('gr-dialog').dispatchEvent(
- new CustomEvent('cancel', {
- composed: true, bubbles: true,
- }));
- assert.isTrue(cancelHandler.called);
- assert.isTrue(cancelHandler.calledOnce);
- assert.isTrue(element._handleCancelTap.called);
- assert.isTrue(element._handleCancelTap.calledOnce);
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.ts
new file mode 100644
index 0000000..08dda14
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-confirm-abandon-dialog/gr-confirm-abandon-dialog_test.ts
@@ -0,0 +1,66 @@
+/**
+ * @license
+ * Copyright (C) 2017 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 '../../../test/common-test-setup-karma';
+import './gr-confirm-abandon-dialog';
+import {GrConfirmAbandonDialog} from './gr-confirm-abandon-dialog';
+import {queryAndAssert} from '../../../test/test-utils';
+import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
+
+const basicFixture = fixtureFromElement('gr-confirm-abandon-dialog');
+
+suite('gr-confirm-abandon-dialog tests', () => {
+ let element: GrConfirmAbandonDialog;
+
+ setup(() => {
+ element = basicFixture.instantiate();
+ });
+
+ test('_handleConfirmTap', () => {
+ const confirmHandler = sinon.stub();
+ element.addEventListener('confirm', confirmHandler);
+ const confirmTapSpy = sinon.spy(element, '_handleConfirmTap');
+ const confirmSpy = sinon.spy(element, '_confirm');
+ queryAndAssert<GrDialog>(element, 'gr-dialog').dispatchEvent(
+ new CustomEvent('confirm', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(confirmHandler.called);
+ assert.isTrue(confirmHandler.calledOnce);
+ assert.isTrue(confirmTapSpy.called);
+ assert.isTrue(confirmSpy.called);
+ assert.isTrue(confirmSpy.calledOnce);
+ });
+
+ test('_handleCancelTap', () => {
+ const cancelHandler = sinon.stub();
+ element.addEventListener('cancel', cancelHandler);
+ const cancelTapSpy = sinon.spy(element, '_handleCancelTap');
+ queryAndAssert<GrDialog>(element, 'gr-dialog').dispatchEvent(
+ new CustomEvent('cancel', {
+ composed: true,
+ bubbles: true,
+ })
+ );
+ assert.isTrue(cancelHandler.called);
+ assert.isTrue(cancelHandler.calledOnce);
+ assert.isTrue(cancelTapSpy.called);
+ assert.isTrue(cancelTapSpy.calledOnce);
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index a090aee..b061043 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -25,15 +25,14 @@
import {appContext} from '../../../services/app-context';
import {
ChangeInfo,
- BranchInfo,
- RepoName,
BranchName,
+ RepoName,
CommitId,
ChangeInfoId,
} from '../../../types/common';
import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
import {customElement, property, observe} from '@polymer/decorators';
-import {AutocompleteSuggestion} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {GrTypedAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete';
import {HttpMethod, ChangeStatus} from '../../../constants/constants';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {fireEvent} from '../../../utils/event-util';
@@ -68,7 +67,7 @@
export interface GrConfirmCherrypickDialog {
$: {
- branchInput: HTMLElement;
+ branchInput: GrTypedAutocomplete<BranchName>;
};
}
@@ -91,7 +90,7 @@
*/
@property({type: String})
- branch?: BranchName;
+ branch = '' as BranchName;
@property({type: String})
baseCommit?: string;
@@ -106,7 +105,7 @@
commitNum?: CommitId;
@property({type: String})
- message?: string;
+ message = '';
@property({type: String})
project?: RepoName;
@@ -115,7 +114,7 @@
changes: ChangeInfo[] = [];
@property({type: Object})
- _query: (input: string) => Promise<AutocompleteSuggestion[]>;
+ _query?: (input: string) => Promise<{name: BranchName}[]>;
@property({type: Boolean})
_showCherryPickTopic = false;
@@ -249,7 +248,7 @@
cherryPickType: CherryPickType,
duplicateProjectChanges: boolean,
statuses: Statuses,
- branch?: BranchName
+ branch: BranchName
) {
if (!branch) return true;
const duplicateProject =
@@ -298,6 +297,9 @@
let newMessage = commitMessage;
if (changeStatus === 'MERGED') {
+ if (!newMessage.endsWith('\n')) {
+ newMessage += '\n';
+ }
newMessage += '(cherry picked from commit ' + commitNum.toString() + ')';
}
this.message = newMessage;
@@ -395,29 +397,22 @@
this.$.branchInput.focus();
}
- _getProjectBranchesSuggestions(
- input: string
- ): Promise<AutocompleteSuggestion[]> {
- if (!this.project) {
- this.reporting.error(new Error('no project specified'));
- return Promise.resolve([]);
- }
+ _getProjectBranchesSuggestions(input: string) {
+ if (!this.project) return Promise.reject(new Error('Missing project'));
if (input.startsWith('refs/heads/')) {
input = input.substring('refs/heads/'.length);
}
return this.restApiService
.getRepoBranches(input, this.project, SUGGESTIONS_LIMIT)
- .then((response: BranchInfo[] | undefined) => {
+ .then(response => {
if (!response) return [];
- const branches = [];
+ const branches: Array<{name: BranchName}> = [];
for (const branchInfo of response) {
- let branch;
- if (branchInfo.ref.startsWith('refs/heads/')) {
- branch = branchInfo.ref.substring('refs/heads/'.length);
- } else {
- branch = branchInfo.ref;
+ let name: string = branchInfo.ref;
+ if (name.startsWith('refs/heads/')) {
+ name = name.substring('refs/heads/'.length);
}
- branches.push({name: branch});
+ branches.push({name: name as BranchName});
}
return branches;
});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
index 1034674..1256cc1 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
@@ -46,6 +46,16 @@
element.project = 'test-project';
});
+ test('with message missing newline', () => {
+ element.changeStatus = 'MERGED';
+ element.commitMessage = 'message';
+ element.commitNum = '123';
+ element.branch = 'master';
+ flush();
+ const expectedMessage = 'message\n(cherry picked from commit 123)';
+ assert.equal(element.message, expectedMessage);
+ });
+
test('with merged change', () => {
element.changeStatus = 'MERGED';
element.commitMessage = 'message\n';
@@ -105,28 +115,26 @@
current_revision: 'a',
},
];
- setup(() => {
+ setup(async () => {
element.updateChanges(changes);
element._cherryPickType = CHERRY_PICK_TYPES.TOPIC;
- flush();
+ await flush();
});
- test('cherry pick topic submit', done => {
+ test('cherry pick topic submit', async () => {
element.branch = 'master';
const executeChangeActionStub = stubRestApi(
'executeChangeAction').returns(Promise.resolve([]));
MockInteractions.tap(element.shadowRoot.
querySelector('gr-dialog').$.confirm);
- flush(() => {
- const args = executeChangeActionStub.args[0];
- assert.equal(args[0], 1);
- assert.equal(args[1], 'POST');
- assert.equal(args[2], '/cherrypick');
- assert.equal(args[4].destination, 'master');
- assert.isTrue(args[4].allow_conflicts);
- assert.isTrue(args[4].allow_empty);
- done();
- });
+ await flush();
+ const args = executeChangeActionStub.args[0];
+ assert.equal(args[0], 1);
+ assert.equal(args[1], 'POST');
+ assert.equal(args[2], '/cherrypick');
+ assert.equal(args[4].destination, 'master');
+ assert.isTrue(args[4].allow_conflicts);
+ assert.isTrue(args[4].allow_empty);
});
test('deselecting a change removes it from being cherry picked', () => {
@@ -171,18 +179,16 @@
), 'error');
});
- test('submit button is blocked while cherry picks is running', done => {
+ test('submit button is blocked while cherry picks is running', async () => {
const confirmButton = element.shadowRoot.querySelector('gr-dialog').$
.confirm;
assert.isTrue(confirmButton.hasAttribute('disabled'));
element.branch = 'b';
- flush();
+ await flush();
assert.isFalse(confirmButton.hasAttribute('disabled'));
element.updateStatus(changes[0], {status: 'RUNNING'});
- flush(() => {
- assert.isTrue(confirmButton.hasAttribute('disabled'));
- done();
- });
+ await flush();
+ assert.isTrue(confirmButton.hasAttribute('disabled'));
});
});
@@ -192,12 +198,11 @@
assert.isTrue(focusStub.called);
});
- test('_getProjectBranchesSuggestions non-empty', done => {
- element._getProjectBranchesSuggestions('test-branch').then(branches => {
- assert.equal(branches.length, 1);
- assert.equal(branches[0].name, 'test-branch');
- done();
- });
+ test('_getProjectBranchesSuggestions non-empty', async () => {
+ const branches = await element._getProjectBranchesSuggestions(
+ 'test-branch');
+ assert.equal(branches.length, 1);
+ assert.equal(branches[0].name, 'test-branch');
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
index eb4053a..8e6521d 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -21,14 +21,25 @@
import {htmlTemplate} from './gr-confirm-move-dialog_html';
import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {customElement, property} from '@polymer/decorators';
-import {RepoName, BranchName} from '../../../types/common';
-import {AutocompleteSuggestion} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {BranchName, RepoName} from '../../../types/common';
import {appContext} from '../../../services/app-context';
+import {GrTypedAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete';
const SUGGESTIONS_LIMIT = 15;
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
+// This is used to make sure 'branch'
+// can be typed as BranchName.
+export interface GrConfirmMoveDialog {
+ $: {
+ branchInput: GrTypedAutocomplete<BranchName>;
+ };
+}
+
@customElement('gr-confirm-move-dialog')
-export class GrConfirmMoveDialog extends KeyboardShortcutMixin(PolymerElement) {
+export class GrConfirmMoveDialog extends base {
static get template() {
return htmlTemplate;
}
@@ -46,16 +57,16 @@
*/
@property({type: String})
- branch?: BranchName;
+ branch = '' as BranchName;
@property({type: String})
- message?: string;
+ message = '';
@property({type: String})
project?: RepoName;
@property({type: Object})
- _query: (input: string) => Promise<AutocompleteSuggestion[]>;
+ _query?: (input: string) => Promise<{name: BranchName}[]>;
get keyBindings() {
return {
@@ -92,9 +103,7 @@
);
}
- _getProjectBranchesSuggestions(
- input: string
- ): Promise<AutocompleteSuggestion[]> {
+ _getProjectBranchesSuggestions(input: string) {
if (!this.project) return Promise.reject(new Error('Missing project'));
if (input.startsWith('refs/heads/')) {
input = input.substring('refs/heads/'.length);
@@ -102,21 +111,15 @@
return this.restApiService
.getRepoBranches(input, this.project, SUGGESTIONS_LIMIT)
.then(response => {
- const branches: AutocompleteSuggestion[] = [];
- let branch;
- if (response) {
- response.forEach(value => {
- if (value.ref.startsWith('refs/heads/')) {
- branch = value.ref.substring('refs/heads/'.length);
- } else {
- branch = value.ref;
- }
- branches.push({
- name: branch,
- });
- });
+ if (!response) return [];
+ const branches: Array<{name: BranchName}> = [];
+ for (const branchInfo of response) {
+ let name: string = branchInfo.ref;
+ if (name.startsWith('refs/heads/')) {
+ name = name.substring('refs/heads/'.length);
+ }
+ branches.push({name: name as BranchName});
}
-
return branches;
});
}
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js
deleted file mode 100644
index 36a2ad3..0000000
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 '../../../test/common-test-setup-karma.js';
-import './gr-confirm-move-dialog.js';
-import {stubRestApi} from '../../../test/test-utils.js';
-
-const basicFixture = fixtureFromElement('gr-confirm-move-dialog');
-
-suite('gr-confirm-move-dialog tests', () => {
- let element;
-
- setup(() => {
- stubRestApi('getRepoBranches').callsFake(input => {
- if (input.startsWith('test')) {
- return Promise.resolve([
- {
- ref: 'refs/heads/test-branch',
- revision: '67ebf73496383c6777035e374d2d664009e2aa5c',
- can_delete: true,
- },
- ]);
- } else {
- return Promise.resolve(undefined);
- }
- });
- element = basicFixture.instantiate();
- element.project = 'test-project';
- });
-
- test('with updated commit message', () => {
- element.branch = 'master';
- const myNewMessage = 'updated commit message';
- element.message = myNewMessage;
- flush();
- assert.equal(element.message, myNewMessage);
- });
-
- test('_getProjectBranchesSuggestions empty', done => {
- element._getProjectBranchesSuggestions('nonexistent').then(branches => {
- assert.equal(branches.length, 0);
- done();
- });
- });
-
- test('_getProjectBranchesSuggestions non-empty', done => {
- element._getProjectBranchesSuggestions('test-branch').then(branches => {
- assert.equal(branches.length, 1);
- assert.equal(branches[0].name, 'test-branch');
- done();
- });
- });
-
- test('_getProjectBranchesSuggestions input empty string', done => {
- element._getProjectBranchesSuggestions('').then(branches => {
- assert.equal(branches.length, 0);
- done();
- });
- });
-});
-
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.ts
new file mode 100644
index 0000000..ea5d320
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_test.ts
@@ -0,0 +1,74 @@
+/**
+ * @license
+ * Copyright (C) 2017 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 '../../../test/common-test-setup-karma';
+import './gr-confirm-move-dialog';
+import {GrConfirmMoveDialog} from './gr-confirm-move-dialog';
+import {stubRestApi} from '../../../test/test-utils';
+import {BranchName, GitRef, RepoName} from '../../../types/common';
+
+const basicFixture = fixtureFromElement('gr-confirm-move-dialog');
+
+suite('gr-confirm-move-dialog tests', () => {
+ let element: GrConfirmMoveDialog;
+
+ setup(() => {
+ stubRestApi('getRepoBranches').callsFake((input: string) => {
+ if (input.startsWith('test')) {
+ return Promise.resolve([
+ {
+ ref: 'refs/heads/test-branch' as GitRef,
+ revision: '67ebf73496383c6777035e374d2d664009e2aa5c',
+ can_delete: true,
+ },
+ ]);
+ } else {
+ return Promise.resolve([]);
+ }
+ });
+ element = basicFixture.instantiate();
+ element.project = 'test-repo' as RepoName;
+ });
+
+ test('with updated commit message', () => {
+ element.branch = 'master' as BranchName;
+ const myNewMessage = 'updated commit message';
+ element.message = myNewMessage;
+ flush();
+ assert.equal(element.message, myNewMessage);
+ });
+
+ test('_getProjectBranchesSuggestions empty', async () => {
+ const branches = await element._getProjectBranchesSuggestions(
+ 'nonexistent'
+ );
+ assert.equal(branches.length, 0);
+ });
+
+ test('_getProjectBranchesSuggestions non-empty', async () => {
+ const branches = await element._getProjectBranchesSuggestions(
+ 'test-branch'
+ );
+ assert.equal(branches.length, 1);
+ assert.equal(branches[0].name, 'test-branch');
+ });
+
+ test('_getProjectBranchesSuggestions input empty string', async () => {
+ const branches = await element._getProjectBranchesSuggestions('');
+ assert.equal(branches.length, 0);
+ });
+});
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
index 95169ca..3ab9c82 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog.ts
@@ -25,11 +25,12 @@
import {pluralize} from '../../../utils/string-util';
import {CommentThread, isUnresolved} from '../../../utils/comment-util';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, query} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property, query} from 'lit/decorators';
+import {fontStyles} from '../../../styles/gr-font-styles';
@customElement('gr-confirm-submit-dialog')
-export class GrConfirmSubmitDialog extends GrLitElement {
+export class GrConfirmSubmitDialog extends LitElement {
@query('#dialog')
dialog?: GrDialog;
@@ -57,9 +58,10 @@
@property({type: Boolean})
_initialised = false;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
#dialog {
min-width: 40em;
@@ -152,7 +154,7 @@
`;
}
- render() {
+ override render() {
return html` <gr-dialog
id="dialog"
confirm-label="Continue"
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
index 968800d..d0865c9 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-download-commands/gr-download-commands';
import {PolymerElement} from '@polymer/polymer/polymer-element';
@@ -41,8 +42,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-download-dialog')
-export class GrDownloadDialog extends KeyboardShortcutMixin(PolymerElement) {
+export class GrDownloadDialog extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
index 6e40f84..097fb0e 100644
--- a/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-download-dialog/gr-download-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index ff303e3..bdc6a43 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -60,8 +60,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-file-list-header')
-export class GrFileListHeader extends KeyboardShortcutMixin(PolymerElement) {
+export class GrFileListHeader extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
index bceee27..85f0330 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
@@ -180,50 +180,61 @@
hidden$="[[_computePrefsButtonHidden(diffPrefs, diffPrefsDisabled)]]"
hidden=""
>
- <gr-button
- link=""
- has-tooltip=""
+ <gr-tooltip-content
+ has-tooltip
title="Diff preferences"
- class="prefsButton desktop"
- on-click="_handlePrefsTap"
- ><iron-icon icon="gr-icons:settings"></iron-icon
- ></gr-button>
+ >
+ <gr-button
+ link=""
+
+ class="prefsButton desktop"
+ on-click="_handlePrefsTap"
+ ><iron-icon icon="gr-icons:settings"></iron-icon
+ ></gr-button>
+ </gr-tooltip-content>
</span>
<span class="separator"></span>
</div>
<span class="downloadContainer desktop">
- <gr-button
- link=""
- class="download"
+ <gr-tooltip-content
+ has-tooltip
title="[[createTitle(Shortcut.OPEN_DOWNLOAD_DIALOG,
- ShortcutSection.ACTIONS)]]"
- has-tooltip=""
- on-click="_handleDownloadTap"
- >Download</gr-button
+ ShortcutSection.ACTIONS)]]"
>
+ <gr-button
+ link=""
+ class="download"
+ on-click="_handleDownloadTap"
+ >Download</gr-button
+ >
+ </gr-tooltip-content>
</span>
<template
is="dom-if"
if="[[_fileListActionsVisible(shownFileCount, _maxFilesForBulkActions)]]"
>
- <gr-button
- id="expandBtn"
- link=""
- title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
- ShortcutSection.FILE_LIST)]]"
- has-tooltip=""
- on-click="_expandAllDiffs"
- >Expand All</gr-button
- >
- <gr-button
- id="collapseBtn"
- link=""
- on-click="_collapseAllDiffs"
- title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
- ShortcutSection.FILE_LIST)]]"
- has-tooltip=""
- >Collapse All</gr-button
- >
+ <gr-tooltip-content
+ has-tooltip
+ title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
+ ShortcutSection.FILE_LIST)]]">
+ <gr-button
+ id="expandBtn"
+ link=""
+
+ on-click="_expandAllDiffs"
+ >Expand All</gr-button
+ >
+ <gr-tooltip-content
+ has-tooltip
+ title="[[createTitle(Shortcut.TOGGLE_ALL_INLINE_DIFFS,
+ ShortcutSection.FILE_LIST)]]">
+ <gr-button
+ id="collapseBtn"
+ link=""
+ on-click="_collapseAllDiffs"
+ >Collapse All</gr-button
+ >
+ </gr-tooltip-content>
</template>
<template
is="dom-if"
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
index dd70678..c90cfcc 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
@@ -34,10 +34,8 @@
element = basicFixture.instantiate();
});
- teardown(done => {
- flush(() => {
- done();
- });
+ teardown(async () => {
+ await flush();
});
test('Diff preferences hidden when no prefs or diffPrefsDisabled', () => {
@@ -77,43 +75,41 @@
assert.isTrue(element._collapseAllDiffs.called);
});
- test('show/hide diffs disabled for large amounts of files', done => {
+ test('show/hide diffs disabled for large amounts of files', async () => {
const computeSpy = sinon.spy(element, '_fileListActionsVisible');
element._files = [];
element.changeNum = '42';
element.basePatchNum = 'PARENT';
element.patchNum = '2';
element.shownFileCount = 1;
- flush(() => {
- assert.isTrue(computeSpy.lastCall.returnValue);
- _.times(element._maxFilesForBulkActions + 1, () => {
- element.shownFileCount = element.shownFileCount + 1;
- });
- assert.isFalse(computeSpy.lastCall.returnValue);
- done();
+ await flush();
+ assert.isTrue(computeSpy.lastCall.returnValue);
+ _.times(element._maxFilesForBulkActions + 1, () => {
+ element.shownFileCount = element.shownFileCount + 1;
});
+ assert.isFalse(computeSpy.lastCall.returnValue);
});
- test('fileViewActions are properly hidden', () => {
+ test('fileViewActions are properly hidden', async () => {
const actions = element.shadowRoot
.querySelector('.fileViewActions');
assert.equal(getComputedStyle(actions).display, 'none');
element.filesExpanded = FilesExpandedState.SOME;
- flush();
+ await flush();
assert.notEqual(getComputedStyle(actions).display, 'none');
element.filesExpanded = FilesExpandedState.ALL;
- flush();
+ await flush();
assert.notEqual(getComputedStyle(actions).display, 'none');
element.filesExpanded = FilesExpandedState.NONE;
- flush();
+ await flush();
assert.equal(getComputedStyle(actions).display, 'none');
});
- test('expand/collapse buttons are toggled correctly', () => {
+ test('expand/collapse buttons are toggled correctly', async () => {
// Only the expand button should be visible in the initial state when
// NO files are expanded.
element.shownFileCount = 10;
- flush();
+ await flush();
const expandBtn = element.shadowRoot.querySelector('#expandBtn');
const collapseBtn = element.shadowRoot.querySelector('#collapseBtn');
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
@@ -122,19 +118,19 @@
// Both expand and collapse buttons should be visible when SOME files are
// expanded.
element.filesExpanded = FilesExpandedState.SOME;
- flush();
+ await flush();
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
// Only the collapse button should be visible when ALL files are expanded.
element.filesExpanded = FilesExpandedState.ALL;
- flush();
+ await flush();
assert.equal(getComputedStyle(expandBtn).display, 'none');
assert.notEqual(getComputedStyle(collapseBtn).display, 'none');
// Only the expand button should be visible when NO files are expanded.
element.filesExpanded = FilesExpandedState.NONE;
- flush();
+ await flush();
assert.notEqual(getComputedStyle(expandBtn).display, 'none');
assert.equal(getComputedStyle(collapseBtn).display, 'none');
});
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index b49fceb..40a2e1f 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../../diff/gr-diff-cursor/gr-diff-cursor';
import '../../diff/gr-diff-host/gr-diff-host';
@@ -172,8 +173,11 @@
* @property {number} lines_inserted - fallback to 0 if not present in api
*/
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-file-list')
-export class GrFileList extends KeyboardShortcutMixin(PolymerElement) {
+export class GrFileList extends base {
static get template() {
return htmlTemplate;
}
@@ -1134,7 +1138,7 @@
// Polymer 2: check for undefined
if (
change === undefined ||
- patchRange === undefined ||
+ !patchRange?.patchNum ||
path === undefined ||
editMode === undefined
) {
@@ -1428,11 +1432,9 @@
);
// Find the paths introduced by the new index splices:
- const newFiles = record.indexSplices
- .map(splice =>
- splice.object.slice(splice.index, splice.index + splice.addedCount)
- )
- .reduce((acc, paths) => acc.concat(paths), []);
+ const newFiles = record.indexSplices.flatMap(splice =>
+ splice.object.slice(splice.index, splice.index + splice.addedCount)
+ );
// Required so that the newly created diff view is included in this.diffs.
flush();
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
index 4d04744..35f01d8 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
index 225130f..b8c6cde 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
@@ -17,6 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import '../../diff/gr-comment-api/gr-comment-api.js';
+import '../../shared/gr-date-formatter/gr-date-formatter.js';
import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import './gr-file-list.js';
import {createCommentApiMockWithTemplateElement} from '../../../test/mocks/comment-api.js';
@@ -43,7 +44,6 @@
createParsedChange,
createRevision,
} from '../../../test/test-data-generators.js';
-import sinon from 'sinon/pkg/sinon-esm';
import {createDefaultDiffPrefs} from '../../../constants/constants.js';
import {queryAndAssert} from '../../../utils/common-util.js';
@@ -93,7 +93,7 @@
});
suite('basic tests', () => {
- setup(done => {
+ setup(async () => {
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
stubRestApi('getDiffDrafts').returns(Promise.resolve({}));
@@ -118,7 +118,6 @@
};
saveStub = sinon.stub(element, '_saveReviewedState').callsFake(
() => Promise.resolve());
- done();
});
test('correct number of files are shown', () => {
@@ -943,14 +942,15 @@
assert.equal(collapseStub.lastCall.args[0].length, 1);
});
- test('_expandedFilesChanged', done => {
+ test('_expandedFilesChanged', async () => {
sinon.stub(element, '_reviewFile');
const path = 'path/to/my/file.txt';
+ const promise = mockPromise();
const diffs = [{
path,
style: {},
reload() {
- done();
+ promise.resolve();
},
prefetchDiff() {},
cancel() {},
@@ -964,6 +964,7 @@
}];
sinon.stub(element, 'diffs').get(() => diffs);
element.push('_expandedFiles', {path});
+ await promise;
});
test('_clearCollapsedDiffs', () => {
@@ -1524,7 +1525,7 @@
return diffs;
}
- setup(done => {
+ setup(async () => {
stubRestApi('getPreferences').returns(Promise.resolve({}));
stubRestApi('getDiffComments').returns(Promise.resolve({}));
stubRestApi('getDiffRobotComments').returns(Promise.resolve({}));
@@ -1569,13 +1570,12 @@
patchNum: 2,
};
sinon.stub(window, 'fetch').callsFake(() => Promise.resolve());
- flush();
- done();
+ await flush();
});
test('cursor with individually opened files', async () => {
MockInteractions.keyUpOn(element, 73, null, 'i');
- flush();
+ await flush();
let diffs = await renderAndGetNewDiffs(0);
const diffStops = diffs[0].getCursorStops();
@@ -1588,13 +1588,13 @@
// Tapping content on a line selects the line number.
MockInteractions.tap(dom(
diffStops[10]).querySelectorAll('.contentText')[0]);
- flush();
+ await flush();
assert.isTrue(diffStops[10].classList.contains('target-row'));
// Keyboard shortcuts are still moving the file cursor, not the diff
// cursor.
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
- flush();
+ await flush();
assert.isTrue(diffStops[10].classList.contains('target-row'));
assert.isFalse(diffStops[11].classList.contains('target-row'));
@@ -1602,7 +1602,7 @@
assert.equal(element.fileCursor.index, 1);
MockInteractions.keyUpOn(element, 73, null, 'i');
- flush();
+ await flush();
diffs = await renderAndGetNewDiffs(1);
// Two diffs should be rendered.
@@ -1617,7 +1617,7 @@
test('cursor with toggle all files', async () => {
MockInteractions.keyUpOn(element, 73, 'shift', 'i');
- flush();
+ await flush();
const diffs = await renderAndGetNewDiffs(0);
const diffStops = diffs[0].getCursorStops();
@@ -1631,13 +1631,13 @@
// Tapping content on a line selects the line number.
MockInteractions.tap(dom(
diffStops[10]).querySelectorAll('.contentText')[0]);
- flush();
+ await flush();
assert.isTrue(diffStops[10].classList.contains('target-row'));
// Keyboard shortcuts are still moving the file cursor, not the diff
// cursor.
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
- flush();
+ await flush();
assert.isFalse(diffStops[10].classList.contains('target-row'));
assert.isTrue(diffStops[11].classList.contains('target-row'));
@@ -1662,9 +1662,9 @@
element.root.querySelectorAll('.row:not(.header-row)');
});
- test('n key with some files expanded and no shift key', () => {
+ test('n key with some files expanded and no shift key', async () => {
MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
- flush();
+ await flush();
// Handle N key should return before calling diff cursor functions.
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
@@ -1676,9 +1676,9 @@
assert.equal(element.filesExpanded, 'some');
});
- test('n key with some files expanded and shift key', () => {
+ test('n key with some files expanded and shift key', async () => {
MockInteractions.keyUpOn(fileRows[0], 73, null, 'i');
- flush();
+ await flush();
assert.equal(nextChunkStub.callCount, 0);
MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
@@ -1690,9 +1690,9 @@
assert.equal(element.filesExpanded, 'some');
});
- test('n key without all files expanded and shift key', () => {
+ test('n key without all files expanded and shift key', async () => {
MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
- flush();
+ await flush();
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
assert.isTrue(nKeySpy.called);
@@ -1703,9 +1703,9 @@
assert.equal(element.filesExpanded, FilesExpandedState.ALL);
});
- test('n key without all files expanded and no shift key', () => {
+ test('n key without all files expanded and no shift key', async () => {
MockInteractions.keyUpOn(fileRows[0], 73, 'shift', 'i');
- flush();
+ await flush();
MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
assert.isTrue(nKeySpy.called);
@@ -1717,7 +1717,7 @@
});
});
- test('_openSelectedFile behavior', () => {
+ test('_openSelectedFile behavior', async () => {
const _filesByPath = element._filesByPath;
element.set('_filesByPath', {});
const navStub = sinon.stub(GerritNav, 'navigateToDiff');
@@ -1726,7 +1726,7 @@
assert.isFalse(navStub.called);
element.set('_filesByPath', _filesByPath);
- flush();
+ await flush();
// Navigates when a file is selected.
element._openSelectedFile();
assert.isTrue(navStub.called);
@@ -1754,7 +1754,7 @@
});
suite('editMode behavior', () => {
- test('reviewed checkbox', () => {
+ test('reviewed checkbox', async () => {
element._reviewFile.restore();
const saveReviewStub = sinon.stub(element, '_saveReviewedState');
@@ -1763,7 +1763,7 @@
assert.isTrue(saveReviewStub.calledOnce);
element.editMode = true;
- flush();
+ await flush();
MockInteractions.pressAndReleaseKeyOn(element, 82, null, 'r');
assert.isTrue(saveReviewStub.calledOnce);
@@ -1779,13 +1779,13 @@
});
});
- test('editing actions', () => {
+ test('editing actions', async () => {
// Edit controls are guarded behind a dom-if initially and not rendered.
assert.isNotOk(dom(element.root)
.querySelector('gr-edit-file-controls'));
element.editMode = true;
- flush();
+ await flush();
// Commit message should not have edit controls.
const editControls =
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index c11e484..d50e00f 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
import '../../../styles/shared-styles';
+import '../../../styles/gr-font-styles';
import '../../shared/gr-button/gr-button';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-included-in-dialog_html';
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
index 2029209..674b7e7 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
background-color: var(--dialog-background-color);
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
index 283a133..4e02155 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_test.ts
@@ -76,7 +76,7 @@
]);
});
- test('_computeGroups with .bindValue', done => {
+ test('_computeGroups with .bindValue', async () => {
queryAndAssert<IronInputElement>(element, '#filterInput')!.bindValue =
'stable-3.2';
const includedIn = {branches: [], tags: []} as IncludedInInfo;
@@ -84,14 +84,10 @@
'master' as BranchName,
'stable-3.2' as BranchName
);
-
- setTimeout(() => {
- const filterText = element._filterText;
- assert.deepEqual(element._computeGroups(includedIn, filterText), [
- {title: 'Branches', items: ['stable-3.2']},
- ]);
-
- done();
- });
+ await flush();
+ const filterText = element._filterText;
+ assert.deepEqual(element._computeGroups(includedIn, filterText), [
+ {title: 'Branches', items: ['stable-3.2']},
+ ]);
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
index 02416ff..9a38095 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row.ts
@@ -16,7 +16,6 @@
*/
import '@polymer/iron-selector/iron-selector';
import '../../shared/gr-button/gr-button';
-import '../../../styles/gr-voting-styles';
import '../../../styles/shared-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-label-score-row_html';
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
index c53f386..0af2f36 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_html.ts
@@ -17,9 +17,6 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="gr-voting-styles">
- /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
- </style>
<style include="shared-styles">
.labelNameCell,
.buttonsCell,
@@ -48,58 +45,37 @@
gr-button {
min-width: 42px;
box-sizing: border-box;
- --gr-button: {
- background-color: var(
- --button-background-color,
- var(--table-header-background-color)
- );
- padding: 0 var(--spacing-m);
- @apply --vote-chip-styles;
- }
}
- gr-button.iron-selected[vote='max'] {
+ gr-button::part(paper-button) {
+ background-color: var(
+ --button-background-color,
+ var(--table-header-background-color)
+ );
+ padding: 0 var(--spacing-m);
+ }
+ gr-tooltip-content.iron-selected > gr-button[vote='max'] {
--button-background-color: var(--vote-color-approved);
}
- gr-button.iron-selected[vote='positive'] {
+ gr-tooltip-content.iron-selected > gr-buttonvote='positive'] {
--button-background-color: var(--vote-color-recommended);
- --gr-button: {
- padding: 0 var(--spacing-m);
- border-style: solid;
- border-color: var(--vote-outline-recommended);
- border-top-left-radius: 1em;
- border-top-right-radius: 1em;
- border-bottom-right-radius: 1em;
- border-bottom-left-radius: 1em;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- color: var(--chip-color);
- }
}
- gr-button.iron-selected[vote='min'] {
+ gr-tooltip-content.iron-selected > gr-button[vote='min'] {
--button-background-color: var(--vote-color-rejected);
}
- gr-button.iron-selected[vote='negative'] {
+ gr-tooltip-content.iron-selected > gr-button[vote='negative'] {
--button-background-color: var(--vote-color-disliked);
- --gr-button: {
- padding: 0 var(--spacing-m);
- border-style: solid;
- border-color: var(--vote-outline-disliked);
- border-top-left-radius: 1em;
- border-top-right-radius: 1em;
- border-bottom-right-radius: 1em;
- border-bottom-left-radius: 1em;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- color: var(--chip-color);
- }
}
- gr-button.iron-selected[vote='neutral'] {
+ gr-tooltip-content.iron-selected > gr-button[vote='neutral'] {
--button-background-color: var(--vote-color-neutral);
}
+ gr-tooltip-content.iron-selected
+ > gr-button[vote='positive']::part(paper-button) {
+ border-color: var(--vote-outline-recommended);
+ }
+ gr-tooltip-content.iron-selected
+ > gr-button[vote='negative']::part(paper-button) {
+ border-color: var(--vote-outline-disliked);
+ }
.placeholder {
display: inline-block;
width: 42px;
@@ -142,16 +118,20 @@
aria-labelledby="labelName"
>
<template is="dom-repeat" items="[[_items]]" as="value">
- <gr-button
- role="radio"
- vote$="[[_computeVoteAttribute(value, index, _items.length)]]"
- has-tooltip=""
+ <gr-tooltip-content
+ has-tooltip
+ title$="[[_computeLabelValueTitle(labels, label.name, value)]]"
data-name$="[[label.name]]"
data-value$="[[value]]"
- title$="[[_computeLabelValueTitle(labels, label.name, value)]]"
>
- [[value]]</gr-button
- >
+ <gr-button
+ role="radio"
+ vote$="[[_computeVoteAttribute(value, index, _items.length)]]"
+ voteChip
+ >
+ [[value]]
+ </gr-button>
+ </gr-tooltip-content>
</template>
</iron-selector>
<template
diff --git a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.js b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.js
index 3c9b7c7..34e959b 100644
--- a/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.js
+++ b/polygerrit-ui/app/elements/change/gr-label-score-row/gr-label-score-row_test.js
@@ -23,7 +23,7 @@
suite('gr-label-row-score tests', () => {
let element;
- setup(done => {
+ setup(async () => {
element = basicFixture.instantiate();
element.labels = {
'Code-Review': {
@@ -80,7 +80,7 @@
value: '+1',
};
- flush(done);
+ await flush();
});
function checkAriaCheckedValid() {
@@ -97,14 +97,14 @@
}
}
- test('label picker', () => {
+ test('label picker', async () => {
const labelsChangedHandler = sinon.stub();
element.addEventListener('labels-changed', labelsChangedHandler);
assert.ok(element.$.labelSelector);
MockInteractions.tap(element.shadowRoot
.querySelector(
- 'gr-button[data-value="-1"]'));
- flush();
+ 'gr-tooltip-content[data-value="-1"] > gr-button'));
+ await flush();
assert.strictEqual(element.selectedValue, '-1');
assert.strictEqual(element.selectedItem
.textContent.trim(), '-1');
@@ -160,26 +160,6 @@
checkAriaCheckedValid();
});
- test('do not display tooltips on touch devices', () => {
- const verifiedBtn = element.shadowRoot
- .querySelector(
- 'iron-selector > gr-button[data-value="-1"]');
-
- // On touch devices, tooltips should not be shown.
- verifiedBtn._isTouchDevice = true;
- verifiedBtn._handleShowTooltip();
- assert.isNotOk(verifiedBtn._tooltip);
- verifiedBtn._handleHideTooltip();
- assert.isNotOk(verifiedBtn._tooltip);
-
- // On other devices, tooltips should be shown.
- verifiedBtn._isTouchDevice = false;
- verifiedBtn._handleShowTooltip();
- assert.isOk(verifiedBtn._tooltip);
- verifiedBtn._handleHideTooltip();
- assert.isNotOk(verifiedBtn._tooltip);
- });
-
test('_computeLabelValue', () => {
assert.strictEqual(element._computeLabelValue(element.labels,
element.permittedLabels,
@@ -209,7 +189,7 @@
'Code-Review'), []);
});
- test('changes in label score are reflected in the DOM', () => {
+ test('changes in label score are reflected in the DOM', async () => {
element.labels = {
'Code-Review': {
values: {
@@ -232,16 +212,17 @@
default_value: 0,
},
};
+ await flush();
const selector = element.$.labelSelector;
element.set('label', {name: 'Verified', value: ' 0'});
- flush();
+ await flush();
assert.strictEqual(selector.selected, ' 0');
assert.strictEqual(
element.$.selectedValueLabel.textContent.trim(), 'No score');
checkAriaCheckedValid();
});
- test('without permitted labels', () => {
+ test('without permitted labels', async () => {
element.permittedLabels = {
Verified: [
'-1',
@@ -249,22 +230,22 @@
'+1',
],
};
- flush();
+ await flush();
assert.isOk(element.$.labelSelector);
assert.isFalse(element.$.labelSelector.hidden);
element.permittedLabels = {};
- flush();
+ await flush();
assert.isOk(element.$.labelSelector);
assert.isTrue(element.$.labelSelector.hidden);
element.permittedLabels = {Verified: []};
- flush();
+ await flush();
assert.isOk(element.$.labelSelector);
assert.isTrue(element.$.labelSelector.hidden);
});
- test('asymmetrical labels', done => {
+ test('asymmetrical labels', async () => {
element.permittedLabels = {
'Code-Review': [
'-2',
@@ -278,35 +259,32 @@
'+1',
],
};
- flush(() => {
- assert.strictEqual(element.$.labelSelector
- .items.length, 2);
- assert.strictEqual(
- element.root.querySelectorAll('.placeholder').length,
- 3);
+ await flush();
+ assert.strictEqual(element.$.labelSelector
+ .items.length, 2);
+ assert.strictEqual(
+ element.root.querySelectorAll('.placeholder').length,
+ 3);
- element.permittedLabels = {
- 'Code-Review': [
- ' 0',
- '+1',
- ],
- 'Verified': [
- '-2',
- '-1',
- ' 0',
- '+1',
- '+2',
- ],
- };
- flush(() => {
- assert.strictEqual(element.$.labelSelector
- .items.length, 5);
- assert.strictEqual(
- element.root.querySelectorAll('.placeholder').length,
- 0);
- done();
- });
- });
+ element.permittedLabels = {
+ 'Code-Review': [
+ ' 0',
+ '+1',
+ ],
+ 'Verified': [
+ '-2',
+ '-1',
+ ' 0',
+ '+1',
+ '+2',
+ ],
+ };
+ await flush();
+ assert.strictEqual(element.$.labelSelector
+ .items.length, 5);
+ assert.strictEqual(
+ element.root.querySelectorAll('.placeholder').length,
+ 0);
});
test('default_value', () => {
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 4147cc0..a496be5 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
@@ -16,9 +16,8 @@
*/
import '../gr-label-score-row/gr-label-score-row';
import '../../../styles/shared-styles';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-label-scores_html';
-import {customElement, property} from '@polymer/decorators';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {hasOwnProperty} from '../../../utils/common-util';
import {
LabelNameToValueMap,
@@ -33,21 +32,14 @@
Label,
LabelValuesMap,
} from '../gr-label-score-row/gr-label-score-row';
-import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {appContext} from '../../../services/app-context';
import {labelCompare} from '../../../utils/label-util';
import {Execution} from '../../../constants/reporting';
+import {ChangeStatus} from '../../../constants/constants';
@customElement('gr-label-scores')
-export class GrLabelScores extends PolymerElement {
- static get template() {
- return htmlTemplate;
- }
-
- @property({type: Array, computed: '_computeLabels(change.labels.*, account)'})
- _labels: Label[] = [];
-
- @property({type: Object, observer: '_computeColumns'})
+export class GrLabelScores extends LitElement {
+ @property({type: Object})
permittedLabels?: LabelNameToValueMap;
@property({type: Object})
@@ -56,11 +48,63 @@
@property({type: Object})
account?: AccountInfo;
- @property({type: Object})
- _labelValues?: LabelValuesMap;
-
private readonly reporting = appContext.reportingService;
+ static override get styles() {
+ return [
+ css`
+ .scoresTable {
+ display: table;
+ width: 100%;
+ }
+ .mergedMessage,
+ .abandonedMessage {
+ font-style: italic;
+ text-align: center;
+ width: 100%;
+ }
+ gr-label-score-row:hover {
+ background-color: var(--hover-background-color);
+ }
+ gr-label-score-row {
+ display: table-row;
+ }
+ gr-label-score-row.no-access {
+ display: none;
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ const labels = this._computeLabels();
+ const labelValues = this._computeColumns();
+ return html`<div class="scoresTable">
+ ${labels.map(
+ label => html`<gr-label-score-row
+ class="${this.computeLabelAccessClass(label.name)}"
+ .label="${label}"
+ .name="${label.name}"
+ .labels="${this.change?.labels}"
+ .permittedLabels="${this.permittedLabels}"
+ .labelValues="${labelValues}"
+ ></gr-label-score-row>`
+ )}
+ </div>
+ <div
+ class="mergedMessage"
+ ?hidden=${this.change?.status !== ChangeStatus.MERGED}
+ >
+ Because this change has been merged, votes may not be decreased.
+ </div>
+ <div
+ class="abandonedMessage"
+ ?hidden=${this.change?.status !== ChangeStatus.ABANDONED}
+ >
+ Because this change has been abandoned, you cannot vote.
+ </div>`;
+ }
+
getLabelValues(includeDefaults = true): LabelNameToValuesMap {
const labels: LabelNameToValuesMap = {};
if (this.shadowRoot === null || !this.change) {
@@ -79,7 +123,7 @@
if (selectedVal === undefined) continue;
- const defValNum = this._getDefaultValue(this.change.labels, label);
+ const defValNum = this.getDefaultValue(label);
if (includeDefaults || selectedVal !== defValNum) {
labels[label] = selectedVal;
}
@@ -87,7 +131,7 @@
return labels;
}
- _getStringLabelValue(
+ private getStringLabelValue(
labels: LabelNameToInfoMap,
labelName: string,
numberValue?: number
@@ -108,25 +152,26 @@
return stringVal;
}
- _getDefaultValue(labels?: LabelNameToInfoMap, labelName?: string) {
+ private getDefaultValue(labelName?: string) {
+ const labels = this.change?.labels;
if (!labelName || !labels?.[labelName]) return undefined;
const labelInfo = labels[labelName] as DetailedLabelInfo;
return labelInfo.default_value;
}
- _getVoteForAccount(
- labels: LabelNameToInfoMap | undefined,
- labelName: string,
- account?: AccountInfo
- ): string | null {
+ _getVoteForAccount(labelName: string): string | null {
+ const labels = this.change?.labels;
if (!labels) return null;
const votes = labels[labelName] as DetailedLabelInfo;
if (votes.all && votes.all.length > 0) {
for (let i = 0; i < votes.all.length; i++) {
- // TODO(TS): Replace == with === and check code can assign string to _account_id instead of number
- // eslint-disable-next-line eqeqeq
- if (account && votes.all[i]._account_id == account._account_id) {
- return this._getStringLabelValue(
+ if (
+ this.account &&
+ // TODO(TS): Replace == with === and check code can assign string to _account_id instead of number
+ // eslint-disable-next-line eqeqeq
+ votes.all[i]._account_id == this.account._account_id
+ ) {
+ return this.getStringLabelValue(
labels,
labelName,
votes.all[i].value
@@ -137,32 +182,26 @@
return null;
}
- _computeLabels(
- labelRecord: PolymerDeepPropertyChange<
- LabelNameToInfoMap,
- LabelNameToInfoMap
- >,
- account?: AccountInfo
- ): Label[] {
- if (!account) return [];
- if (!labelRecord?.base) return [];
- const labelsObj = labelRecord.base;
+ _computeLabels(): Label[] {
+ if (!this.account) return [];
+ const labelsObj = this.change?.labels;
+ if (!labelsObj) return [];
return Object.keys(labelsObj)
.sort(labelCompare)
.map(key => {
return {
name: key,
- value: this._getVoteForAccount(labelsObj, key, this.account),
+ value: this._getVoteForAccount(key),
};
});
}
- _computeColumns(permittedLabels?: LabelNameToValueMap) {
- if (!permittedLabels) return;
- const labels = Object.keys(permittedLabels);
+ _computeColumns() {
+ if (!this.permittedLabels) return;
+ const labels = Object.keys(this.permittedLabels);
const values: Set<number> = new Set();
for (const label of labels) {
- for (const value of permittedLabels[label]) {
+ for (const value of this.permittedLabels[label]) {
values.add(Number(value));
}
}
@@ -173,23 +212,14 @@
for (let i = 0; i < orderedValues.length; i++) {
labelValues[orderedValues[i]] = i;
}
- this._labelValues = labelValues;
+ return labelValues;
}
- _changeIsMerged(changeStatus: string) {
- return changeStatus === 'MERGED';
- }
+ private computeLabelAccessClass(label?: string) {
+ if (!this.permittedLabels || !label) return '';
- _computeLabelAccessClass(
- label?: string,
- permittedLabels?: LabelNameToValueMap
- ) {
- if (!permittedLabels || !label) {
- return '';
- }
-
- return hasOwnProperty(permittedLabels, label) &&
- permittedLabels[label].length
+ return hasOwnProperty(this.permittedLabels, label) &&
+ this.permittedLabels[label].length
? 'access'
: 'no-access';
}
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_html.ts b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_html.ts
deleted file mode 100644
index 7b1fb7f..0000000
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_html.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style include="shared-styles">
- .scoresTable {
- display: table;
- width: 100%;
- }
- .mergedMessage {
- font-style: italic;
- text-align: center;
- width: 100%;
- }
- gr-label-score-row:hover {
- background-color: var(--hover-background-color);
- }
- gr-label-score-row {
- display: table-row;
- }
- gr-label-score-row.no-access {
- display: none;
- }
- </style>
- <div class="scoresTable">
- <template is="dom-repeat" items="[[_labels]]" as="label">
- <gr-label-score-row
- class$="[[_computeLabelAccessClass(label.name, permittedLabels)]]"
- label="[[label]]"
- name="[[label.name]]"
- labels="[[change.labels]]"
- permitted-labels="[[permittedLabels]]"
- label-values="[[_labelValues]]"
- ></gr-label-score-row>
- </template>
- </div>
- <div class="mergedMessage" hidden$="[[!_changeIsMerged(change.status)]]">
- Because this change has been merged, votes may not be decreased.
- </div>
-`;
diff --git a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.ts b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.ts
index 58fe189..f529464 100644
--- a/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-label-scores/gr-label-scores_test.ts
@@ -17,7 +17,7 @@
import '../../../test/common-test-setup-karma';
import './gr-label-scores';
-import {queryAndAssert, stubRestApi} from '../../../test/test-utils';
+import {isHidden, queryAndAssert, stubRestApi} from '../../../test/test-utils';
import {GrLabelScores} from './gr-label-scores';
import {AccountId} from '../../../types/common';
import {GrLabelScoreRow} from '../gr-label-score-row/gr-label-score-row';
@@ -25,6 +25,7 @@
createAccountWithId,
createChange,
} from '../../../test/test-data-generators';
+import {ChangeStatus} from '../../../constants/constants';
const basicFixture = fixtureFromElement('gr-label-scores');
@@ -84,7 +85,7 @@
await flush();
});
- test('get and set label scores', () => {
+ test('get and set label scores', async () => {
for (const label of Object.keys(element.permittedLabels!)) {
const row = queryAndAssert<GrLabelScoreRow>(
element,
@@ -92,6 +93,7 @@
);
row.setSelectedValue('-1');
}
+ await flush();
assert.deepEqual(element.getLabelValues(), {
'Code-Review': -1,
Verified: -1,
@@ -116,19 +118,12 @@
test('_getVoteForAccount', () => {
const labelName = 'Code-Review';
- assert.strictEqual(
- element._getVoteForAccount(
- element.change!.labels,
- labelName,
- element.account
- ),
- '+1'
- );
+ assert.strictEqual(element._getVoteForAccount(labelName), '+1');
});
test('_computeColumns', () => {
- element._computeColumns(element.permittedLabels);
- assert.deepEqual(element._labelValues, {
+ const labelValues = element._computeColumns();
+ assert.deepEqual(labelValues, {
'-2': 0,
'-1': 1,
'0': 2,
@@ -137,31 +132,8 @@
});
});
- test('_computeLabelAccessClass undefined case', () => {
- assert.strictEqual(
- element._computeLabelAccessClass(undefined, undefined),
- ''
- );
- assert.strictEqual(element._computeLabelAccessClass('', undefined), '');
- assert.strictEqual(element._computeLabelAccessClass(undefined, {}), '');
- });
-
- test('_computeLabelAccessClass has access', () => {
- assert.strictEqual(
- element._computeLabelAccessClass('foo', {foo: ['']}),
- 'access'
- );
- });
-
- test('_computeLabelAccessClass no access', () => {
- assert.strictEqual(
- element._computeLabelAccessClass('zap', {foo: ['']}),
- 'no-access'
- );
- });
-
- test('changes in label score are reflected in _labels', () => {
- element.change = {
+ test('changes in label score are reflected in _labels', async () => {
+ const change = {
...createChange(),
labels: {
'Code-Review': {
@@ -186,17 +158,62 @@
},
},
};
- assert.deepEqual(element._labels, [
+ element.change = change;
+ await flush();
+ let labels = element._computeLabels();
+ assert.deepEqual(labels, [
{name: 'Code-Review', value: null},
{name: 'Verified', value: null},
]);
- element.set(
- ['change', 'labels', 'Verified', 'all'],
- [{_account_id: accountId, value: 1}]
- );
- assert.deepEqual(element._labels, [
+ element.change = {
+ ...change,
+ labels: {
+ ...change.labels,
+ Verified: {
+ ...change.labels.Verified,
+ all: [
+ {
+ _account_id: accountId,
+ value: 1,
+ },
+ ],
+ },
+ },
+ };
+ await flush();
+ labels = element._computeLabels();
+ assert.deepEqual(labels, [
{name: 'Code-Review', value: null},
{name: 'Verified', value: '+1'},
]);
});
+ suite('message', () => {
+ test('shown when change is abandoned', async () => {
+ element.change = {
+ ...createChange(),
+ status: ChangeStatus.ABANDONED,
+ };
+ await flush();
+ assert.isFalse(isHidden(queryAndAssert(element, '.abandonedMessage')));
+ assert.isTrue(isHidden(queryAndAssert(element, '.mergedMessage')));
+ });
+ test('shown when change is merged', async () => {
+ element.change = {
+ ...createChange(),
+ status: ChangeStatus.MERGED,
+ };
+ await flush();
+ assert.isFalse(isHidden(queryAndAssert(element, '.mergedMessage')));
+ assert.isTrue(isHidden(queryAndAssert(element, '.abandonedMessage')));
+ });
+ test('do not show for new', async () => {
+ element.change = {
+ ...createChange(),
+ status: ChangeStatus.NEW,
+ };
+ await flush();
+ assert.isTrue(isHidden(queryAndAssert(element, '.mergedMessage')));
+ assert.isTrue(isHidden(queryAndAssert(element, '.abandonedMessage')));
+ });
+ });
});
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
index 94295d0..95e4301 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
@@ -22,7 +22,6 @@
import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../shared/gr-formatted-text/gr-formatted-text';
import '../../../styles/shared-styles';
-import '../../../styles/gr-voting-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-message_html';
import {MessageTag, SpecialFilePath} from '../../../constants/constants';
@@ -181,7 +180,7 @@
@property({
type: String,
computed:
- '_computeMessageContentExpanded(message.message,' +
+ '_computeMessageContentExpanded(_expanded, message.message,' +
' message.accounts_in_message,' +
' message.tag)',
})
@@ -210,7 +209,7 @@
this.addEventListener('click', e => this._handleClick(e));
}
- connectedCallback() {
+ override connectedCallback() {
super.connectedCallback();
this.restApiService.getConfig().then(config => {
this.config = config;
@@ -241,10 +240,12 @@
}
_computeMessageContentExpanded(
+ expanded: boolean,
content?: string,
accountsInMessage?: AccountInfo[],
tag?: ReviewInputTag
) {
+ if (!expanded) return '';
return this._computeMessageContent(true, content, accountsInMessage, tag);
}
@@ -278,9 +279,11 @@
tag?: ReviewInputTag,
commentThreads?: CommentThread[]
) {
+ // Content is under text-overflow, so it's always shorten
+ const shortenedContent = content?.substring(0, 1000);
const summary = this._computeMessageContent(
false,
- content,
+ shortenedContent,
accountsInMessage,
tag
);
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
index 9e24a09..c9680ef 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
@@ -17,9 +17,6 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
- <style include="gr-voting-styles">
- /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
- </style>
<style>
:host {
display: block;
@@ -248,13 +245,13 @@
<template is="dom-if" if="[[message.message]]">
<div class="content messageContent">
<div class="message hideOnOpen">[[_messageContentCollapsed]]</div>
- <gr-formatted-text
- noTrailingMargin
- class="message hideOnCollapsed"
- content="[[_messageContentExpanded]]"
- config="[[_projectConfig.commentlinks]]"
- ></gr-formatted-text>
<template is="dom-if" if="[[_expanded]]">
+ <gr-formatted-text
+ noTrailingMargin
+ class="message hideOnCollapsed"
+ content="[[_messageContentExpanded]]"
+ config="[[_projectConfig.commentlinks]]"
+ ></gr-formatted-text>
<template is="dom-if" if="[[_messageContentExpanded]]">
<div
class="replyActionContainer"
@@ -284,8 +281,8 @@
</template>
<gr-thread-list
change="[[change]]"
- hidden$="[[!message.commentThreads.length]]"
- threads="[[message.commentThreads]]"
+ hidden$="[[!commentThreads.length]]"
+ threads="[[commentThreads]]"
change-num="[[changeNum]]"
logged-in="[[_loggedIn]]"
hide-dropdown
@@ -328,8 +325,8 @@
<template is="dom-if" if="[[!message.id]]">
<span class="date">
<gr-date-formatter
- has-tooltip=""
- show-date-and-time=""
+ withTooltip
+ showDateAndTime
date-str="[[message.date]]"
></gr-date-formatter>
</span>
@@ -337,8 +334,8 @@
<template is="dom-if" if="[[message.id]]">
<span class="date" on-click="_handleAnchorClick">
<gr-date-formatter
- has-tooltip=""
- show-date-and-time=""
+ withTooltip
+ showDateAndTime
date-str="[[message.date]]"
></gr-date-formatter>
</span>
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts
index cae7a5a..f87c4c3 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_test.ts
@@ -26,6 +26,7 @@
createRevisions,
} from '../../../test/test-data-generators';
import {
+ mockPromise,
query,
queryAll,
queryAndAssert,
@@ -50,7 +51,7 @@
} from '../../../types/events';
import {GrButton} from '../../shared/gr-button/gr-button';
import {CommentSide} from '../../../constants/constants';
-import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonStubbedMember} from 'sinon';
const basicFixture = fixtureFromElement('gr-message');
@@ -58,13 +59,13 @@
let element: GrMessage;
suite('when admin and logged in', () => {
- setup(done => {
+ setup(async () => {
stubRestApi('getIsAdmin').returns(Promise.resolve(true));
element = basicFixture.instantiate();
- flush(done);
+ await flush();
});
- test('reply event', done => {
+ test('reply event', async () => {
element.message = {
...createChangeMessage(),
id: '47c43261_55aa2c41' as ChangeMessageId,
@@ -79,18 +80,20 @@
expanded: true,
};
+ const promise = mockPromise();
element.addEventListener('reply', (e: CustomEvent<ReplyEventDetail>) => {
assert.deepEqual(e.detail.message, element.message);
- done();
+ promise.resolve();
});
- flush();
+ await flush();
assert.isFalse(
queryAndAssert<HTMLElement>(element, '.replyActionContainer').hidden
);
tap(queryAndAssert(element, '.replyBtn'));
+ await promise;
});
- test('can see delete button', () => {
+ test('can see delete button', async () => {
element.message = {
...createChangeMessage(),
id: '47c43261_55aa2c41' as ChangeMessageId,
@@ -105,11 +108,11 @@
expanded: true,
};
- flush();
+ await flush();
assert.isFalse(queryAndAssert<HTMLElement>(element, '.deleteBtn').hidden);
});
- test('delete change message', done => {
+ test('delete change message', async () => {
element.changeNum = 314159 as NumericChangeId;
element.message = {
...createChangeMessage(),
@@ -125,6 +128,7 @@
expanded: true,
};
+ const promise = mockPromise();
element.addEventListener(
'change-message-deleted',
(e: CustomEvent<ChangeMessageDeletedEventDetail>) => {
@@ -132,14 +136,15 @@
assert.isFalse(
(queryAndAssert(element, '.deleteBtn') as GrButton).disabled
);
- done();
+ promise.resolve();
}
);
- flush();
+ await flush();
tap(queryAndAssert(element, '.deleteBtn'));
assert.isTrue(
(queryAndAssert(element, '.deleteBtn') as GrButton).disabled
);
+ await promise;
});
test('autogenerated prefix hiding', () => {
@@ -565,11 +570,11 @@
});
suite('when not logged in', () => {
- setup(done => {
+ setup(async () => {
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
stubRestApi('getIsAdmin').returns(Promise.resolve(false));
element = basicFixture.instantiate();
- flush(done);
+ await flush();
});
test('reply and delete button should be hidden', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
index fae624e..fdd7c79 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts
@@ -90,27 +90,19 @@
*/
function computeThreads(
message: CombinedMessage,
- changeComments?: ChangeComments
+ allThreadsForChange: CommentThread[]
): CommentThread[] {
- if (message._index === undefined || changeComments === undefined) {
+ if (message._index === undefined) {
return [];
}
const messageId = getMessageId(message);
- return changeComments.getAllThreadsForChange().filter(thread =>
- thread.comments
- .map(comment => {
- // collapse all by default
- comment.collapsed = true;
- return comment;
- })
- .some(comment => {
- const condition = comment.change_message_id === messageId;
- // Since getAllThreadsForChange() always returns a new copy of
- // all comments we can modify them here without worrying about
- // polluting other threads.
- comment.collapsed = !condition;
- return condition;
- })
+ return allThreadsForChange.filter(thread =>
+ thread.comments.some(comment => {
+ const matchesMessage = comment.change_message_id === messageId;
+ if (!matchesMessage) return false;
+ comment.collapsed = !matchesMessage;
+ return matchesMessage;
+ })
);
}
@@ -198,7 +190,6 @@
}
export const TEST_ONLY = {
- computeThreads,
computeTag,
computeRevision,
computeIsImportant,
@@ -210,8 +201,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-messages-list')
-export class GrMessagesList extends KeyboardShortcutMixin(PolymerElement) {
+export class GrMessagesList extends base {
static get template() {
return htmlTemplate;
}
@@ -352,14 +346,24 @@
mDate = null;
}
}
- combinedMessages.forEach(m => {
- if (m.expanded === undefined) {
- m.expanded = false;
+
+ const allThreadsForChange = changeComments.getAllThreadsForChange();
+ // collapse all by default
+ for (const thread of allThreadsForChange) {
+ for (const comment of thread.comments) {
+ comment.collapsed = true;
}
- m.commentThreads = computeThreads(m, changeComments);
- m._revision_number = computeRevision(m, combinedMessages);
- m.tag = computeTag(m);
- });
+ }
+
+ for (let i = 0; i < combinedMessages.length; i++) {
+ const message = combinedMessages[i];
+ if (message.expanded === undefined) {
+ message.expanded = false;
+ }
+ message.commentThreads = computeThreads(message, allThreadsForChange);
+ message._revision_number = computeRevision(message, combinedMessages);
+ message.tag = computeTag(message);
+ }
// computeIsImportant() depends on tags and revision numbers already being
// updated for all messages, so we have to compute this in its own forEach
// loop.
@@ -369,10 +373,6 @@
return combinedMessages;
}
- getCommentThreads(message: CombinedMessage, changeComments?: ChangeComments) {
- return computeThreads(message, changeComments);
- }
-
_updateExpandedStateOfAllMessages(exp: boolean) {
if (this._combinedMessages) {
for (let i = 0; i < this._combinedMessages.length; i++) {
@@ -438,24 +438,26 @@
}
/**
- * This method is for reporting stats only.
+ * Called when this._combinedMessages has changed.
*/
_combinedMessagesChanged(combinedMessages?: CombinedMessage[]) {
- if (combinedMessages) {
- if (combinedMessages.length === 0) return;
- const tags = combinedMessages.map(
- message =>
- message.tag || (message as FormattedReviewerUpdateInfo).type || 'none'
- );
- const tagsCounted = tags.reduce(
- (acc, val) => {
- acc[val] = (acc[val] || 0) + 1;
- return acc;
- },
- {all: combinedMessages.length} as TagsCountReportInfo
- );
- this.reporting.reportInteraction('messages-count', tagsCounted);
+ if (!combinedMessages) return;
+ if (combinedMessages.length === 0) return;
+ for (let i = 0; i < combinedMessages.length; i++) {
+ this.notifyPath(`_combinedMessages.${i}.commentThreads`);
}
+ const tags = combinedMessages.map(
+ message =>
+ message.tag || (message as FormattedReviewerUpdateInfo).type || 'none'
+ );
+ const tagsCounted = tags.reduce(
+ (acc, val) => {
+ acc[val] = (acc[val] || 0) + 1;
+ return acc;
+ },
+ {all: combinedMessages.length} as TagsCountReportInfo
+ );
+ this.reporting.reportInteraction('messages-count', tagsCounted);
}
/**
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
index 93df77e..56fae87 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list_html.ts
@@ -93,7 +93,7 @@
change="[[change]]"
change-num="[[changeNum]]"
message="[[message]]"
- comment-threads="[[getCommentThreads(message, changeComments)]]"
+ comment-threads="[[message.commentThreads]]"
project-name="[[projectName]]"
show-reply-button="[[showReplyButtons]]"
on-message-anchor-tap="_handleAnchorClick"
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-change.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-change.ts
index b3730fd..d34600e 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-change.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-change.ts
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property, css} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {sharedStyles} from '../../../styles/shared-styles';
import {
ChangeInfo,
@@ -27,7 +26,7 @@
import {isChangeInfo} from '../../../utils/change-util';
@customElement('gr-related-change')
-export class GrRelatedChange extends GrLitElement {
+export class GrRelatedChange extends LitElement {
@property()
change?: ChangeInfo | RelatedChangeAndCommitInfo;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
index dd86ea1..74f20f2 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
@@ -14,14 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html, nothing} from 'lit-html';
import './gr-related-change';
import '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../../plugins/gr-endpoint-slot/gr-endpoint-slot';
-import {classMap} from 'lit-html/directives/class-map';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property, css, state, TemplateResult} from 'lit-element';
+import {classMap} from 'lit/directives/class-map';
+import {LitElement, css, html, nothing, TemplateResult} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
import {sharedStyles} from '../../../styles/shared-styles';
import {
SubmittedTogetherInfo,
@@ -61,7 +60,7 @@
}
@customElement('gr-related-changes-list')
-export class GrRelatedChangesList extends GrLitElement {
+export class GrRelatedChangesList extends LitElement {
@property()
change?: ParsedChangeInfo;
@@ -666,7 +665,7 @@
}
@customElement('gr-related-collapse')
-export class GrRelatedCollapse extends GrLitElement {
+export class GrRelatedCollapse extends LitElement {
@property()
override title = '';
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
index 15bc6bf..a6dc338f 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonStubbedMember} from 'sinon';
import {PluginApi} from '../../../api/plugin';
import {ChangeStatus} from '../../../constants/constants';
import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
@@ -74,9 +74,9 @@
v: boolean;
}>
) {
- return instructions
- .map(inst => Array.from({length: inst.len}, () => inst.v))
- .reduce((acc, val) => acc.concat(val), []);
+ return instructions.flatMap(inst =>
+ Array.from({length: inst.len}, () => inst.v)
+ );
}
function checkShowWhenCollapsed(
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
index 933cb821..b8c9319 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog-it_test.js
@@ -127,7 +127,7 @@
const labelScoreRows = element.getLabelScores().shadowRoot
.querySelector('gr-label-score-row[name="Code-Review"]');
const selectedBtn = labelScoreRows.shadowRoot
- .querySelector('gr-button[data-value="+1"].iron-selected');
+ .querySelector('gr-tooltip-content[data-value="+1"] > gr-button');
assert.isOk(selectedBtn);
});
});
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 89df2cb..17036e6 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
@@ -163,8 +163,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-reply-dialog')
-export class GrReplyDialog extends KeyboardShortcutMixin(PolymerElement) {
+export class GrReplyDialog extends base {
static get template() {
return htmlTemplate;
}
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 b571985..1973fe6 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
@@ -441,23 +441,26 @@
></gr-account-label>
</template>
</template>
- <gr-button
- class="edit-attention-button"
- on-click="_handleAttentionModify"
- disabled="[[_sendDisabled]]"
- link=""
- position-below=""
- data-label="Edit"
- data-action-type="change"
- data-action-key="edit"
- has-tooltip=""
+ <gr-tooltip-content
+ has-tooltip
title="[[_computeAttentionButtonTitle(_sendDisabled)]]"
- role="button"
- tabindex="0"
>
- <iron-icon icon="gr-icons:edit"></iron-icon>
- Modify
- </gr-button>
+ <gr-button
+ class="edit-attention-button"
+ on-click="_handleAttentionModify"
+ disabled="[[_sendDisabled]]"
+ link=""
+ position-below=""
+ data-label="Edit"
+ data-action-type="change"
+ data-action-key="edit"
+ role="button"
+ tabindex="0"
+ >
+ <iron-icon icon="gr-icons:edit"></iron-icon>
+ Modify
+ </gr-button>
+ </gr-tooltip-content>
</div>
<div>
<a
@@ -612,26 +615,32 @@
<!-- Use 'Send' here as the change may only about reviewers / ccs
and when this button is visible, the next button will always
be 'Start review' -->
- <gr-button
- link=""
- disabled="[[_isState(knownLatestState, 'not-latest')]]"
- class="action save"
+ <gr-tooltip-content
has-tooltip=""
- title="[[_saveTooltip]]"
- on-click="_saveClickHandler"
- >Send As WIP</gr-button
+ title$="[[_saveTooltip]]"
>
+ <gr-button
+ link=""
+ disabled="[[_isState(knownLatestState, 'not-latest')]]"
+ class="action save"
+ on-click="_saveClickHandler"
+ >Send As WIP</gr-button
+ >
+ </gr-tooltip-content>
</template>
- <gr-button
- id="sendButton"
- primary=""
- disabled="[[_sendDisabled]]"
- class="action send"
+ <gr-tooltip-content
has-tooltip=""
title$="[[_computeSendButtonTooltip(canBeStarted, _commentEditing)]]"
- on-click="_sendTapHandler"
- >[[_sendButtonLabel]]</gr-button
>
+ <gr-button
+ id="sendButton"
+ primary=""
+ disabled="[[_sendDisabled]]"
+ class="action send"
+ on-click="_sendTapHandler"
+ >[[_sendButtonLabel]]
+ </gr-button>
+ </gr-tooltip-content>
</div>
</section>
</div>
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
index d70c7ba..e57ffc7 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.ts
@@ -116,7 +116,7 @@
return {id: `${lastId++}` as GroupId};
};
- setup(() => {
+ setup(async () => {
changeNum = 42 as NumericChangeId;
patchNum = 1 as PatchSetNum;
@@ -168,7 +168,7 @@
// .returns(Promise.resolve({isLatest: true}));
// Allow the elements created by dom-repeat to be stamped.
- flush();
+ await flush();
});
function stubSaveReview(
@@ -216,6 +216,7 @@
// which the dom-repeat elements are stamped.
await flush();
tap(queryAndAssert(element, '.send'));
+ await flush();
const review = await saveReviewPromise;
assert.deepEqual(review, {
@@ -1037,45 +1038,40 @@
});
});
- test('getlabelValue returns value', done => {
- flush(() => {
- const el = queryAndAssert(
- queryAndAssert(element, 'gr-label-scores'),
- 'gr-label-score-row[name="Verified"]'
- ) as GrLabelScoreRow;
- el.setSelectedValue('-1');
- assert.equal('-1', element.getLabelValue('Verified'));
- done();
- });
+ test('getlabelValue returns value', async () => {
+ await flush();
+ const el = queryAndAssert(
+ queryAndAssert(element, 'gr-label-scores'),
+ 'gr-label-score-row[name="Verified"]'
+ ) as GrLabelScoreRow;
+ el.setSelectedValue('-1');
+ assert.equal('-1', element.getLabelValue('Verified'));
});
- test('getlabelValue when no score is selected', done => {
- flush(() => {
- const el = queryAndAssert(
- queryAndAssert(element, 'gr-label-scores'),
- 'gr-label-score-row[name="Code-Review"]'
- ) as GrLabelScoreRow;
- el.setSelectedValue('-1');
- assert.strictEqual(element.getLabelValue('Verified'), ' 0');
- done();
- });
+ test('getlabelValue when no score is selected', async () => {
+ await flush();
+ const el = queryAndAssert(
+ queryAndAssert(element, 'gr-label-scores'),
+ 'gr-label-score-row[name="Code-Review"]'
+ ) as GrLabelScoreRow;
+ el.setSelectedValue('-1');
+ assert.strictEqual(element.getLabelValue('Verified'), ' 0');
});
- test('setlabelValue', done => {
+ test('setlabelValue', async () => {
element._account = {_account_id: 1 as AccountId};
- flush(() => {
- const label = 'Verified';
- const value = '+1';
- element.setLabelValue(label, value);
+ await flush();
+ const label = 'Verified';
+ const value = '+1';
+ element.setLabelValue(label, value);
+ await flush();
- const labels = (
- queryAndAssert(element, '#labelScores') as GrLabelScores
- ).getLabelValues();
- assert.deepEqual(labels, {
- 'Code-Review': 0,
- Verified: 1,
- });
- done();
+ const labels = (
+ queryAndAssert(element, '#labelScores') as GrLabelScores
+ ).getLabelValues();
+ assert.deepEqual(labels, {
+ 'Code-Review': 0,
+ Verified: 1,
});
});
@@ -1347,7 +1343,7 @@
assert.isTrue(eraseDraftCommentStub.calledWith(location));
});
- test('400 converts to human-readable server-error', done => {
+ test('400 converts to human-readable server-error', async () => {
stubRestApi('saveChangeReview').callsFake(
(_changeNum, _patchNum, _review, errFn) => {
errFn!(
@@ -1360,34 +1356,35 @@
}
);
+ const promise = mockPromise();
const listener = (event: Event) => {
if (event.target !== document) return;
(event as CustomEvent).detail.response.text().then((body: string) => {
if (body === 'human readable') {
- done();
+ promise.resolve();
}
});
};
addListenerForTest(document, 'server-error', listener);
- flush(() => {
- element.send(false, false);
- });
+ await flush();
+ element.send(false, false);
+ await promise;
});
- test('non-json 400 is treated as a normal server-error', done => {
+ test('non-json 400 is treated as a normal server-error', async () => {
stubRestApi('saveChangeReview').callsFake(
(_changeNum, _patchNum, _review, errFn) => {
errFn!(cloneableResponse(400, 'Comment validation error!') as Response);
return Promise.resolve(new Response());
}
);
-
+ const promise = mockPromise();
const listener = (event: Event) => {
if (event.target !== document) return;
(event as CustomEvent).detail.response.text().then((body: string) => {
if (body === 'Comment validation error!') {
- done();
+ promise.resolve();
}
});
};
@@ -1395,9 +1392,9 @@
// Async tick is needed because iron-selector content is distributed and
// distributed content requires an observer to be set up.
- flush(() => {
- element.send(false, false);
- });
+ await flush();
+ element.send(false, false);
+ await promise;
});
test('filterReviewerSuggestion', () => {
@@ -1494,29 +1491,30 @@
assert.strictEqual(element._chooseFocusTarget(), element.FocusTarget.BODY);
});
- test('only send labels that have changed', done => {
- flush(() => {
- stubSaveReview((review: ReviewInput) => {
- assert.deepEqual(review?.labels, {
- 'Code-Review': 0,
- Verified: -1,
- });
+ test('only send labels that have changed', async () => {
+ await flush();
+ stubSaveReview((review: ReviewInput) => {
+ assert.deepEqual(review?.labels, {
+ 'Code-Review': 0,
+ Verified: -1,
});
-
- element.addEventListener('send', () => {
- done();
- });
- // Without wrapping this test in flush(), the below two calls to
- // tap() cause a race in some situations in shadow DOM.
- // The send button can be tapped before the others, causing the test to
- // fail.
- const el = queryAndAssert(
- queryAndAssert(element, 'gr-label-scores'),
- 'gr-label-score-row[name="Verified"]'
- ) as GrLabelScoreRow;
- el.setSelectedValue('-1');
- tap(queryAndAssert(element, '.send'));
});
+
+ const promise = mockPromise();
+ element.addEventListener('send', () => {
+ promise.resolve();
+ });
+ // Without wrapping this test in flush(), the below two calls to
+ // tap() cause a race in some situations in shadow DOM.
+ // The send button can be tapped before the others, causing the test to
+ // fail.
+ const el = queryAndAssert(
+ queryAndAssert(element, 'gr-label-scores'),
+ 'gr-label-score-row[name="Verified"]'
+ ) as GrLabelScoreRow;
+ el.setSelectedValue('-1');
+ tap(queryAndAssert(element, '.send'));
+ await promise;
});
test('moving from cc to reviewer', () => {
@@ -1811,14 +1809,14 @@
stubSaveReview(() => undefined);
element.addEventListener('send', () => assert.fail('wrongly called'));
pressAndReleaseKeyOn(element, 13, null, 'enter');
- flush();
});
- test('emit send on ctrl+enter key', done => {
+ test('emit send on ctrl+enter key', async () => {
stubSaveReview(() => undefined);
- element.addEventListener('send', () => done());
+ const promise = mockPromise();
+ element.addEventListener('send', () => promise.resolve());
pressAndReleaseKeyOn(element, 13, 'ctrl', 'enter');
- flush();
+ await promise;
});
test('_computeMessagePlaceholder', () => {
@@ -1840,7 +1838,7 @@
);
});
- test('_handle400Error reviewers and CCs', done => {
+ test('_handle400Error reviewers and CCs', async () => {
const error1 = 'error 1';
const error2 = 'error 2';
const error3 = 'error 3';
@@ -1862,49 +1860,48 @@
},
},
});
+ const promise = mockPromise();
const listener = (e: Event) => {
(e as CustomEvent).detail.response.text().then((text: string) => {
assert.equal(text, [error1, error2, error3].join(', '));
- done();
+ promise.resolve();
});
};
addListenerForTest(document, 'server-error', listener);
element._handle400Error(cloneableResponse(400, text) as Response);
+ await promise;
});
- test('fires height change when the drafts comments load', done => {
+ test('fires height change when the drafts comments load', async () => {
// Flush DOM operations before binding to the autogrow event so we don't
// catch the events fired from the initial layout.
- flush(() => {
- const autoGrowHandler = sinon.stub();
- element.addEventListener('autogrow', autoGrowHandler);
- element.draftCommentThreads = [];
- flush(() => {
- assert.isTrue(autoGrowHandler.called);
- done();
- });
- });
+ await flush();
+ const autoGrowHandler = sinon.stub();
+ element.addEventListener('autogrow', autoGrowHandler);
+ element.draftCommentThreads = [];
+ await flush();
+ assert.isTrue(autoGrowHandler.called);
});
suite('start review and save buttons', () => {
let sendStub: sinon.SinonStub;
- setup(() => {
+ setup(async () => {
sendStub = sinon.stub(element, 'send').callsFake(() => Promise.resolve());
element.canBeStarted = true;
// Flush to make both Start/Save buttons appear in DOM.
- flush();
+ await flush();
});
- test('start review sets ready', () => {
+ test('start review sets ready', async () => {
tap(queryAndAssert(element, '.send'));
- flush();
+ await flush();
assert.isTrue(sendStub.calledWith(true, true));
});
- test("save review doesn't set ready", () => {
+ test("save review doesn't set ready", async () => {
tap(queryAndAssert(element, '.save'));
- flush();
+ await flush();
assert.isTrue(sendStub.calledWith(true, false));
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
index c579a59..b081be7 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
@@ -57,6 +57,10 @@
vertical-align: top;
display: inline-block;
}
+ gr-vote-chip {
+ --gr-vote-chip-width: 14px;
+ --gr-vote-chip-height: 14px;
+ }
</style>
<div class="container">
<div>
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts
new file mode 100644
index 0000000..2e00034
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard.ts
@@ -0,0 +1,106 @@
+/**
+ * @license
+ * 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.
+ */
+import '../../../styles/gr-font-styles';
+import '../../shared/gr-hovercard/gr-hovercard-shared-style';
+import '../../shared/gr-button/gr-button';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {customElement, property} from '@polymer/decorators';
+import {HovercardBehaviorMixin} from '../../shared/gr-hovercard/gr-hovercard-behavior';
+import {htmlTemplate} from './gr-submit-requirement-hovercard_html';
+import {
+ AccountInfo,
+ SubmitRequirementExpressionInfo,
+ SubmitRequirementResultInfo,
+ SubmitRequirementStatus,
+} from '../../../api/rest-api';
+import {
+ extractAssociatedLabels,
+ iconForStatus,
+} from '../../../utils/label-util';
+import {ParsedChangeInfo} from '../../../types/types';
+import {Label} from '../gr-change-requirements/gr-change-requirements';
+
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = HovercardBehaviorMixin(PolymerElement);
+
+@customElement('gr-submit-requirement-hovercard')
+export class GrHovercardRun extends base {
+ static get template() {
+ return htmlTemplate;
+ }
+
+ @property({type: Object})
+ requirement?: SubmitRequirementResultInfo;
+
+ @property({type: Object})
+ change?: ParsedChangeInfo;
+
+ @property({type: Object})
+ account?: AccountInfo;
+
+ @property({type: Boolean})
+ mutable = false;
+
+ @property({type: Boolean})
+ expanded = false;
+
+ @property({type: Array, computed: 'computeLabels(change, requirement)'})
+ _labels: Label[] = [];
+
+ computeLabels(
+ change?: ParsedChangeInfo,
+ requirement?: SubmitRequirementResultInfo
+ ) {
+ if (!requirement) return [];
+ const requirementLabels = extractAssociatedLabels(requirement);
+ const labels = change?.labels ?? {};
+
+ const allLabels: Label[] = [];
+
+ for (const label of Object.keys(labels)) {
+ if (requirementLabels.includes(label)) {
+ allLabels.push({
+ labelName: label,
+ icon: '',
+ style: '',
+ labelInfo: labels[label],
+ });
+ }
+ }
+ return allLabels;
+ }
+
+ computeIcon(status: SubmitRequirementStatus) {
+ return iconForStatus(status);
+ }
+
+ renderCondition(expression?: SubmitRequirementExpressionInfo) {
+ if (!expression) return '';
+
+ return expression.expression;
+ }
+
+ _handleShowConditions() {
+ this.expanded = true;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'gr-submit-requirement-hovercard': GrHovercardRun;
+ }
+}
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts
new file mode 100644
index 0000000..192a812
--- /dev/null
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirement-hovercard/gr-submit-requirement-hovercard_html.ts
@@ -0,0 +1,189 @@
+/**
+ * @license
+ * 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.
+ */
+import {html} from '@polymer/polymer/lib/utils/html-tag';
+
+export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
+ <style include="gr-hovercard-shared-style">
+ #container {
+ min-width: 356px;
+ max-width: 356px;
+ padding: var(--spacing-xl) 0 var(--spacing-m) 0;
+ }
+ section.label {
+ display: table-row;
+ }
+ .label-title {
+ min-width: 10em;
+ padding-top: var(--spacing-s);
+ }
+ .label-value {
+ padding-top: var(--spacing-s);
+ }
+ .label-title,
+ .label-value {
+ display: table-cell;
+ vertical-align: top;
+ }
+ .row {
+ display: flex;
+ }
+ .title {
+ color: var(--deemphasized-text-color);
+ margin-right: var(--spacing-m);
+ }
+ div.section {
+ margin: 0 var(--spacing-xl) var(--spacing-m) var(--spacing-xl);
+ display: flex;
+ }
+ div.sectionIcon {
+ flex: 0 0 30px;
+ }
+ div.sectionIcon iron-icon {
+ position: relative;
+ top: 2px;
+ width: 20px;
+ height: 20px;
+ }
+ .condition {
+ background-color: var(--gray-background);
+ padding: var(--spacing-m);
+ flex-grow: 1;
+ }
+ .expression {
+ color: var(--gray-foreground);
+ }
+ iron-icon.check {
+ color: var(--success-foreground);
+ }
+ iron-icon.close {
+ color: var(--warning-foreground);
+ }
+ .showConditions iron-icon {
+ color: inherit;
+ }
+ div.showConditions {
+ border-top: 1px solid var(--border-color);
+ margin-top: var(--spacing-m);
+ padding: var(--spacing-m) var(--spacing-xl) 0;
+ }
+ </style>
+ <div id="container" role="tooltip" tabindex="-1">
+ <div class="section">
+ <div class="sectionIcon">
+ <iron-icon
+ class$="[[computeIcon(requirement.status)]]"
+ icon="gr-icons:[[computeIcon(requirement.status)]]"
+ ></iron-icon>
+ </div>
+ <div class="sectionContent">
+ <h3 class="name heading-3">
+ <span>[[requirement.name]]</span>
+ </h3>
+ </div>
+ </div>
+ <div class="section">
+ <div class="sectionIcon">
+ <iron-icon class="small" icon="gr-icons:info-outline"></iron-icon>
+ </div>
+ <div class="sectionContent">
+ <div class="row">
+ <div class="title">Status</div>
+ <div>[[requirement.status]]</div>
+ </div>
+ </div>
+ </div>
+ <div class="section">
+ <template is="dom-repeat" items="[[_labels]]">
+ <section class="label">
+ <div class="label-title">
+ <gr-limited-text
+ class="name"
+ limit="25"
+ text="[[item.labelName]]"
+ ></gr-limited-text>
+ </div>
+ <div class="label-value">
+ <gr-label-info
+ change="{{change}}"
+ account="[[account]]"
+ mutable="[[mutable]]"
+ label="[[item.labelName]]"
+ label-info="[[item.labelInfo]]"
+ ></gr-label-info>
+ </div>
+ </section>
+ </template>
+ </div>
+ <template is="dom-if" if="[[!expanded]]">
+ <div class="showConditions">
+ <gr-button
+ link=""
+ class="showConditions"
+ on-click="_handleShowConditions"
+ >
+ View condition
+ <iron-icon icon="gr-icons:expand-more"></iron-icon
+ ></gr-button>
+ </div>
+ </template>
+ <template is="dom-if" if="[[expanded]]">
+ <div class="section">
+ <div class="sectionIcon">
+ <iron-icon icon="gr-icons:description"></iron-icon>
+ </div>
+ <div class="sectionContent">[[requirement.description]]</div>
+ </div>
+ <div class="section">
+ <div class="sectionIcon"></div>
+ <div class="sectionContent condition">
+ Blocking condition:<br />
+ <span class="expression">
+ [[renderCondition(requirement.submittability_expression_result)]]
+ </span>
+ </div>
+ </div>
+ <template
+ is="dom-if"
+ if="[[requirement.applicability_expression_result]]"
+ >
+ <div class="section">
+ <div class="sectionIcon"></div>
+ <div class="sectionContent condition">
+ Application condition:<br />
+ <span class="expression">
+ [[renderCondition(requirement.applicability_expression_result)]]
+ </span>
+ </div>
+ </div>
+ </template>
+ <template is="dom-if" if="[[requirement.override_expression_result]]">
+ <div class="section">
+ <div class="sectionIcon"></div>
+ <div class="sectionContent condition">
+ Override condition:<br />
+ <span class="expression">
+ [[renderCondition(requirement.override_expression_result)]]
+ </span>
+ </div>
+ </div>
+ </template>
+ </template>
+ </div>
+`;
diff --git a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
index 47f6e85..fd85117 100644
--- a/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
+++ b/polygerrit-ui/app/elements/change/gr-submit-requirements/gr-submit-requirements.ts
@@ -14,20 +14,35 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import '../gr-submit-requirement-hovercard/gr-submit-requirement-hovercard';
+import {LitElement, css, html} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
import {ParsedChangeInfo} from '../../../types/types';
import {
AccountInfo,
+ isDetailedLabelInfo,
+ LabelNameToInfoMap,
SubmitRequirementResultInfo,
SubmitRequirementStatus,
} from '../../../api/rest-api';
-import {assertNever} from '../../../utils/common-util';
-import {extractAssociatedLabels} from '../../../utils/change-metadata-util';
-import {Label} from '../gr-change-requirements/gr-change-requirements';
+import {unique} from '../../../utils/common-util';
+import {
+ extractAssociatedLabels,
+ hasVotes,
+ iconForStatus,
+} from '../../../utils/label-util';
+import {fontStyles} from '../../../styles/gr-font-styles';
+import {charsOnly, pluralize} from '../../../utils/string-util';
+import {subscribe} from '../../lit/subscription-controller';
+import {
+ allRunsLatestPatchsetLatestAttempt$,
+ CheckRun,
+} from '../../../services/checks/checks-model';
+import {getResultsOf, hasResultsOf} from '../../../services/checks/checks-util';
+import {Category} from '../../../api/checks';
@customElement('gr-submit-requirements')
-export class GrSubmitRequirements extends GrLitElement {
+export class GrSubmitRequirements extends LitElement {
@property({type: Object})
change?: ParsedChangeInfo;
@@ -37,48 +52,29 @@
@property({type: Boolean})
mutable?: boolean;
+ @state()
+ runs: CheckRun[] = [];
+
static override get styles() {
return [
+ fontStyles,
css`
- :host {
- display: table;
- width: 100%;
- }
.metadata-title {
- font-size: 100%;
font-weight: var(--font-weight-bold);
color: var(--deemphasized-text-color);
padding-left: var(--metadata-horizontal-padding);
- }
- section {
- display: table-row;
- }
- .title {
- min-width: 10em;
- padding: var(--spacing-s) 0 0 0;
- }
- .value {
- padding: var(--spacing-s) 0 0 0;
- }
- .title,
- .value,
- .status {
- display: table-cell;
- vertical-align: top;
- }
- .status {
- width: var(--line-height-small);
- padding: var(--spacing-s) var(--spacing-m) 0
- var(--requirements-horizontal-padding);
+ margin: 0 0 var(--spacing-s);
+ border-top: 1px solid var(--border-color);
+ padding-top: var(--spacing-s);
}
iron-icon {
- width: var(--line-height-small);
- height: var(--line-height-small);
+ width: var(--line-height-normal, 20px);
+ height: var(--line-height-normal, 20px);
}
- iron-icon.satisfied {
+ iron-icon.check {
color: var(--success-foreground);
}
- iron-icon.unsatisfied {
+ iron-icon.close {
color: var(--warning-foreground);
}
.testing {
@@ -95,79 +91,189 @@
.testing:hover * {
visibility: visible;
}
+ .requirements,
+ section.votes {
+ margin-left: var(--spacing-l);
+ }
+ gr-limited-text.name {
+ font-weight: var(--font-weight-bold);
+ }
+ table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ }
+ td {
+ padding: var(--spacing-s);
+ }
+ .votes-cell {
+ display: flex;
+ }
+ .check-error {
+ margin-right: var(--spacing-l);
+ }
+ .check-error iron-icon {
+ color: var(--error-foreground);
+ vertical-align: top;
+ }
`,
];
}
+ constructor() {
+ super();
+ subscribe(this, allRunsLatestPatchsetLatestAttempt$, x => (this.runs = x));
+ }
+
override render() {
const submit_requirements = (this.change?.submit_requirements ?? []).filter(
req => req.status !== SubmitRequirementStatus.NOT_APPLICABLE
);
- return html`<h3 class="metadata-title">Submit Requirements</h3>
+ return html` <h2
+ class="metadata-title heading-3"
+ id="submit-requirements-caption"
+ >
+ Submit Requirements
+ </h2>
+ <table class="requirements" aria-labelledby="submit-requirements-caption">
+ <thead hidden>
+ <tr>
+ <th>Status</th>
+ <th>Name</th>
+ <th>Votes</th>
+ </tr>
+ </thead>
+ <tbody>
+ ${submit_requirements.map(
+ requirement => html`<tr
+ id="requirement-${charsOnly(requirement.name)}"
+ >
+ <td>${this.renderStatus(requirement.status)}</td>
+ <td class="name">
+ <gr-limited-text
+ class="name"
+ limit="25"
+ .text="${requirement.name}"
+ ></gr-limited-text>
+ </td>
+ <td>
+ <div class="votes-cell">
+ ${this.renderVotes(requirement)}
+ ${this.renderChecks(requirement)}
+ </div>
+ </td>
+ </tr>`
+ )}
+ </tbody>
+ </table>
${submit_requirements.map(
- requirement => html`<section>
- <div class="status">${this.renderStatus(requirement.status)}</div>
- <div class="title">
- <gr-limited-text
- class="name"
- limit="25"
- text="${requirement.name}"
- ></gr-limited-text>
- </div>
- <div class="value">${this.renderLabels(requirement)}</div>
- </section>`
+ requirement => html`
+ <gr-submit-requirement-hovercard
+ for="requirement-${charsOnly(requirement.name)}"
+ .requirement="${requirement}"
+ .change="${this.change}"
+ .account="${this.account}"
+ .mutable="${this.mutable}"
+ ></gr-submit-requirement-hovercard>
+ `
+ )}
+ ${this.renderTriggerVotes(
+ submit_requirements
)}${this.renderFakeControls()}`;
}
renderStatus(status: SubmitRequirementStatus) {
- let grIcon: string;
- switch (status) {
- case SubmitRequirementStatus.SATISFIED:
- grIcon = 'gr-icons:check';
- break;
- case SubmitRequirementStatus.UNSATISFIED:
- grIcon = 'gr-icons:close';
- break;
- case SubmitRequirementStatus.OVERRIDDEN:
- grIcon = 'gr-icons:warning';
- break;
- case SubmitRequirementStatus.NOT_APPLICABLE:
- grIcon = 'gr-icons:info';
- break;
- default:
- assertNever(status, `Unsupported status: ${status}`);
- }
+ const icon = iconForStatus(status);
return html`<iron-icon
- class=${status.toLowerCase()}
- icon="${grIcon}"
+ class="${icon}"
+ icon="gr-icons:${icon}"
+ role="img"
+ aria-label="${status.toLowerCase()}"
></iron-icon>`;
}
- renderLabels(requirement: SubmitRequirementResultInfo) {
+ renderVotes(requirement: SubmitRequirementResultInfo) {
const requirementLabels = extractAssociatedLabels(requirement);
- const labels = this.change?.labels ?? {};
-
- const allLabels: Label[] = [];
-
- for (const label of Object.keys(labels)) {
- if (requirementLabels.includes(label)) {
- allLabels.push({
- labelName: label,
- icon: '',
- style: '',
- labelInfo: labels[label],
- });
- }
- }
- return allLabels.map(
- label => html`<gr-label-info
- .change="${this.change}"
- .account="${this.account}"
- .mutable="${this.mutable}"
- label="${label.labelName}"
- .labelInfo="${label.labelInfo}"
- ></gr-label-info>`
+ const allLabels = this.change?.labels ?? {};
+ const associatedLabels = Object.keys(allLabels).filter(label =>
+ requirementLabels.includes(label)
);
+
+ const everyAssociatedLabelsIsWithoutVotes = associatedLabels.every(
+ label => !hasVotes(allLabels[label])
+ );
+ if (everyAssociatedLabelsIsWithoutVotes) return html`No votes`;
+
+ return associatedLabels.map(label =>
+ this.renderLabelVote(label, allLabels)
+ );
+ }
+
+ renderLabelVote(label: string, labels: LabelNameToInfoMap) {
+ const labelInfo = labels[label];
+ if (!isDetailedLabelInfo(labelInfo)) return;
+ const uniqueApprovals = (labelInfo.all ?? [])
+ .filter(
+ (approvalInfo, index, array) =>
+ index === array.findIndex(other => other.value === approvalInfo.value)
+ )
+ .sort((a, b) => -(a.value ?? 0) + (b.value ?? 0));
+ return uniqueApprovals.map(
+ approvalInfo =>
+ html`<gr-vote-chip
+ .vote="${approvalInfo}"
+ .label="${labelInfo}"
+ .more="${(labelInfo.all ?? []).filter(
+ other => other.value === approvalInfo.value
+ ).length > 1}"
+ ></gr-vote-chip>`
+ );
+ }
+
+ renderChecks(requirement: SubmitRequirementResultInfo) {
+ const requirementLabels = extractAssociatedLabels(requirement);
+ const requirementRuns = this.runs
+ .filter(run => hasResultsOf(run, Category.ERROR))
+ .filter(
+ run => run.labelName && requirementLabels.includes(run.labelName)
+ );
+ const runsCount = requirementRuns.reduce(
+ (sum, run) => sum + getResultsOf(run, Category.ERROR).length,
+ 0
+ );
+ if (runsCount > 0) {
+ return html`<span class="check-error"
+ ><iron-icon icon="gr-icons:error"></iron-icon>${pluralize(
+ runsCount,
+ 'error'
+ )}</span
+ >`;
+ }
+ return;
+ }
+
+ renderTriggerVotes(submitReqs: SubmitRequirementResultInfo[]) {
+ const labels = this.change?.labels ?? {};
+ const allLabels = Object.keys(labels);
+ const labelAssociatedWithSubmitReqs = submitReqs
+ .flatMap(req => extractAssociatedLabels(req))
+ .filter(unique);
+ const triggerVotes = allLabels
+ .filter(label => !labelAssociatedWithSubmitReqs.includes(label))
+ .filter(label => hasVotes(labels[label]));
+ if (!triggerVotes.length) return;
+ return html`<h3 class="metadata-title heading-3">Trigger Votes</h3>
+ <section class="votes">
+ ${triggerVotes.map(
+ label => html`${label}:
+ <gr-label-info
+ .change="${this.change}"
+ .account="${this.account}"
+ .mutable="${this.mutable}"
+ label="${label}"
+ .labelInfo="${labels[label]}"
+ ></gr-label-info>`
+ )}
+ </section>`;
}
renderFakeControls() {
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 daf2643..6ed5a2c 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
@@ -102,9 +102,9 @@
items="[[getCommentsDropdownEntires(threads, loggedIn)]]"
>
</gr-dropdown-list>
- <template is="dom-if" if="[[threads.length]]">
+ <template is="dom-if" if="[[_displayedThreads.length]]">
<span class="author-text">From:</span>
- <template is="dom-repeat" items="[[getCommentAuthors(threads, account)]]">
+ <template is="dom-repeat" items="[[getCommentAuthors(_displayedThreads, account)]]">
<gr-account-label
account="[[item]]"
on-click="handleAccountClicked"
@@ -115,7 +115,7 @@
</template>
</div>
</template>
- <div id="threads">
+ <div id="threads" part="threads">
<template
is="dom-if"
if="[[_showEmptyThreadsMessage(threads, _displayedThreads, unresolvedOnly)]]"
diff --git a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.js b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.js
index fe99918..aab5cee 100644
--- a/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-thread-list/gr-thread-list_test.js
@@ -37,7 +37,7 @@
.filter(e => e.style.display !== 'none');
}
- setup(done => {
+ setup(async () => {
element = basicFixture.instantiate();
element.changeNum = 123;
element.change = {
@@ -267,9 +267,7 @@
];
// use flush to render all (bypass initial-count set on dom-repeat)
- flush(() => {
- done();
- });
+ await flush();
});
test('draft dropdown item only appears when logged in', () => {
@@ -289,14 +287,13 @@
assert.equal(getVisibleThreads().length, element.threads.length);
});
- test('show unresolved threads if unresolvedOnly is set', done => {
+ test('show unresolved threads if unresolvedOnly is set', async () => {
element.unresolvedOnly = true;
- flush();
+ await flush();
const unresolvedThreads = element.threads.filter(t => t.comments.some(
c => c.unresolved
));
assert.equal(getVisibleThreads().length, unresolvedThreads.length);
- done();
});
test('showing file name takes visible threads into account', () => {
@@ -498,15 +495,18 @@
test('tapping single author chips', () => {
element.account = createAccountDetailWithId(1);
flush();
- const chips = queryAll(element, 'gr-account-label');
- const authors = Array.from(chips).map(
+ const chips = Array.from(queryAll(element, 'gr-account-label'));
+ const authors = chips.map(
chip => accountOrGroupKey(chip.account))
.sort();
assert.deepEqual(authors, [1, 1000000, 1000001, 1000002, 1000003]);
assert.equal(element.threads.length, 9);
assert.equal(element._displayedThreads.length, 9);
- tap(chips[0]); // accountId 1000001
+ // accountId 1000001
+ const chip = chips.find(chip => chip.account._account_id === 1000001);
+
+ tap(chip);
flush();
assert.equal(element.threads.length, 9);
@@ -514,7 +514,7 @@
assert.equal(element._displayedThreads[0].comments[0].author._account_id,
1000001);
- tap(chips[0]); // tapping again resets
+ tap(chip); // tapping again resets
flush();
assert.equal(element.threads.length, 9);
assert.equal(element._displayedThreads.length, 9);
@@ -523,10 +523,10 @@
test('tapping multiple author chips', () => {
element.account = createAccountDetailWithId(1);
flush();
- const chips = queryAll(element, 'gr-account-label');
+ const chips = Array.from(queryAll(element, 'gr-account-label'));
- tap(chips[0]); // accountId 1000001
- tap(chips[2]); // accountId 1000002
+ tap(chips.find(chip => chip.account._account_id === 1000001));
+ tap(chips.find(chip => chip.account._account_id === 1000002));
flush();
assert.equal(element.threads.length, 9);
@@ -646,11 +646,9 @@
});
suite('hideDropdown', () => {
- setup(done => {
+ setup(async () => {
element.hideDropdown = true;
- flush(() => {
- done();
- });
+ await flush();
});
test('toggle buttons are hidden', () => {
@@ -660,11 +658,9 @@
});
suite('empty thread', () => {
- setup(done => {
+ setup(async () => {
element.threads = [];
- flush(() => {
- done();
- });
+ await flush();
});
test('default empty message should show', () => {
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-action.ts b/polygerrit-ui/app/elements/checks/gr-checks-action.ts
index 4633c0e..aed07e0 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-action.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-action.ts
@@ -14,20 +14,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {css, customElement, property} from 'lit-element';
-import {GrLitElement} from '../lit/gr-lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {Action} from '../../api/checks';
import {checkRequiredProperty} from '../../utils/common-util';
-import {fireActionTriggered} from '../../services/checks/checks-util';
+import {appContext} from '../../services/app-context';
@customElement('gr-checks-action')
-export class GrChecksAction extends GrLitElement {
+export class GrChecksAction extends LitElement {
@property()
action!: Action;
@property()
- eventTarget?: EventTarget;
+ eventTarget: HTMLElement | null = null;
+
+ private checksService = appContext.checksService;
override connectedCallback() {
super.connectedCallback();
@@ -42,20 +43,13 @@
white-space: nowrap;
}
gr-button {
- /* It is not fully understood why this is needed, but otherwise the
- paper-tooltip may render under some iron-icons of the content
- below. Maybe this has to do with a z-index:0 setting for
- paper-button, such that a stacking context is created. And the high
- z-index of the paper-tooltip will then only be interpreted within
- that stacking context. */
- z-index: 1;
--padding: var(--spacing-s) var(--spacing-m);
}
- gr-button paper-tooltip {
+ paper-tooltip {
text-transform: none;
text-align: center;
white-space: normal;
- width: 200px;
+ max-width: 200px;
}
`,
];
@@ -70,19 +64,23 @@
@click="${(e: Event) => this.handleClick(e)}"
>
${this.action.name}
- <paper-tooltip
- ?hidden="${!this.action.tooltip}"
- offset="5"
- fit-to-visible-bounds="true"
- >${this.action.tooltip}</paper-tooltip
- >
</gr-button>
+ ${this.renderTooltip()}
+ `;
+ }
+
+ private renderTooltip() {
+ if (!this.action.tooltip) return;
+ return html`
+ <paper-tooltip offset="5" fit-to-visible-bounds="true">
+ ${this.action.tooltip}
+ </paper-tooltip>
`;
}
handleClick(e: Event) {
e.stopPropagation();
- fireActionTriggered(this.eventTarget ?? this, this.action);
+ this.checksService.triggerAction(this.action);
}
}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-attempt.ts b/polygerrit-ui/app/elements/checks/gr-checks-attempt.ts
index 6de92e1..b4d87ae 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-attempt.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-attempt.ts
@@ -14,14 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {css, customElement, property} from 'lit-element';
-import {GrLitElement} from '../lit/gr-lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {CheckRun} from '../../services/checks/checks-model';
import {ordinal} from '../../utils/string-util';
@customElement('gr-checks-attempt')
-class GrChecksAttempt extends GrLitElement {
+class GrChecksAttempt extends LitElement {
@property()
run?: CheckRun;
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-results.ts b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
index 08f3907..68c7957 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-results.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-results.ts
@@ -14,20 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {classMap} from 'lit-html/directives/class-map';
-import {repeat} from 'lit-html/directives/repeat';
-import {ifDefined} from 'lit-html/directives/if-defined';
-import {
- css,
- customElement,
- property,
- PropertyValues,
- query,
- state,
- TemplateResult,
-} from 'lit-element';
-import {GrLitElement} from '../lit/gr-lit-element';
+import {classMap} from 'lit/directives/class-map';
+import {repeat} from 'lit/directives/repeat';
+import {ifDefined} from 'lit/directives/if-defined';
+import {LitElement, css, html, PropertyValues, TemplateResult} from 'lit';
+import {customElement, property, query, state} from 'lit/decorators';
import './gr-checks-action';
import '@polymer/paper-tooltip/paper-tooltip';
import {
@@ -49,7 +40,6 @@
} from '../../services/checks/checks-model';
import {
allResults,
- fireActionTriggered,
firstPrimaryLink,
hasCompletedWithoutResults,
iconFor,
@@ -64,7 +54,7 @@
import {modifierPressed, toggleClass, whenVisible} from '../../utils/dom-util';
import {durationString} from '../../utils/date-util';
import {charsOnly} from '../../utils/string-util';
-import {isAttemptSelected} from './gr-checks-util';
+import {isAttemptSelected, matches} from './gr-checks-util';
import {ChecksTabState} from '../../types/events';
import {
ConfigInfo,
@@ -81,9 +71,12 @@
valueString,
} from '../../utils/label-util';
import {GerritNav} from '../core/gr-navigation/gr-navigation';
+import {DropdownLink} from '../shared/gr-dropdown/gr-dropdown';
+import {subscribe} from '../lit/subscription-controller';
+import {fontStyles} from '../../styles/gr-font-styles';
@customElement('gr-result-row')
-class GrResultRow extends GrLitElement {
+class GrResultRow extends LitElement {
@query('td.nameCol div.name')
nameEl?: HTMLElement;
@@ -102,9 +95,11 @@
@property()
labels?: LabelNameToInfoMap;
+ private checksService = appContext.checksService;
+
constructor() {
super();
- this.subscribe('labels', labels$);
+ subscribe(this, labels$, x => (this.labels = x));
}
static override get styles() {
@@ -284,11 +279,10 @@
];
}
- override update(changedProperties: PropertyValues) {
+ override updated(changedProperties: PropertyValues) {
if (changedProperties.has('result')) {
this.isExpandable = !!this.result?.summary && !!this.result?.message;
}
- super.update(changedProperties);
}
override focus() {
@@ -501,7 +495,7 @@
}
private handleAction(e: CustomEvent<Action>) {
- fireActionTriggered(this, e.detail);
+ this.checksService.triggerAction(e.detail);
}
private renderAction(action?: Action) {
@@ -531,14 +525,14 @@
return html`<div class="tag ${tag.color}">
<span>${tag.name}</span>
<paper-tooltip offset="5" fit-to-visible-bounds="true">
- A category tag for this check result
+ ${tag.tooltip ?? 'A category tag for this check result'}
</paper-tooltip>
</div>`;
}
}
@customElement('gr-result-expanded')
-class GrResultExpanded extends GrLitElement {
+class GrResultExpanded extends LitElement {
@property()
result?: RunResult;
@@ -570,7 +564,7 @@
constructor() {
super();
- this.subscribe('repoConfig', repoConfig$);
+ subscribe(this, repoConfig$, x => (this.repoConfig = x));
}
override render() {
@@ -678,7 +672,7 @@
);
@customElement('gr-checks-results')
-export class GrChecksResults extends GrLitElement {
+export class GrChecksResults extends LitElement {
@query('#filterInput')
filterInput?: HTMLInputElement;
@@ -743,17 +737,26 @@
constructor() {
super();
- this.subscribe('actions', topLevelActionsSelected$);
- this.subscribe('links', topLevelLinksSelected$);
- this.subscribe('checksPatchsetNumber', checksSelectedPatchsetNumber$);
- this.subscribe('latestPatchsetNumber', latestPatchNum$);
- this.subscribe('someProvidersAreLoading', someProvidersAreLoadingSelected$);
+ subscribe(this, topLevelActionsSelected$, x => (this.actions = x));
+ subscribe(this, topLevelLinksSelected$, x => (this.links = x));
+ subscribe(
+ this,
+ checksSelectedPatchsetNumber$,
+ x => (this.checksPatchsetNumber = x)
+ );
+ subscribe(this, latestPatchNum$, x => (this.latestPatchsetNumber = x));
+ subscribe(
+ this,
+ someProvidersAreLoadingSelected$,
+ x => (this.someProvidersAreLoading = x)
+ );
}
static override get styles() {
return [
sharedStyles,
spinnerStyles,
+ fontStyles,
css`
:host {
display: block;
@@ -974,6 +977,7 @@
override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const style = html`<style>
.headerTopRow .right .goToLatest gr-button {
--gr-button: {
@@ -1011,11 +1015,7 @@
</div>
<div class="headerBottomRow">
<div class="left">${this.renderFilter()}</div>
- <div class="right">
- ${this.renderLinks()}
- <div class="space"></div>
- ${this.renderActions()}
- </div>
+ <div class="right">${this.renderLinksAndActions()}</div>
</div>
</div>
<div class="body">
@@ -1026,9 +1026,8 @@
</div>`;
}
- private renderLinks() {
+ private renderLinksAndActions() {
const links = this.links ?? [];
- if (links.length === 0) return;
const primaryLinks = links
.filter(a => a.primary)
// Showing the same icons twice without text is super confusing.
@@ -1038,14 +1037,7 @@
)
.slice(0, 4);
const overflowLinks = links.filter(a => !primaryLinks.includes(a));
- return html`
- ${primaryLinks.map(this.renderLink)}
- ${this.renderOverflowLinks(overflowLinks)}
- `;
- }
-
- private renderOverflowLinks(overflowLinks: Link[]) {
- const items = overflowLinks.map(link => {
+ const overflowLinkItems = overflowLinks.map(link => {
return {
...link,
id: link.tooltip,
@@ -1054,18 +1046,27 @@
tooltip: undefined,
};
});
+
+ const actions = this.actions ?? [];
+ const primaryActions = actions.filter(a => a.primary).slice(0, 2);
+ const overflowActions = actions.filter(a => !primaryActions.includes(a));
+ const overflowActionItems = overflowActions.map(action => {
+ return {...action, id: action.name};
+ });
+ const disabledActions = overflowActionItems
+ .filter(action => action.disabled)
+ .map(action => action.id);
+
return html`
- <gr-dropdown
- id="moreLinks"
- link=""
- vertical-offset="32"
- horizontal-align="right"
- .items="${items}"
- >
- <iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
- </iron-icon>
- <span id="moreMessage">More</span>
- </gr-dropdown>
+ ${primaryLinks.map(this.renderLink)}
+ ${primaryLinks.length > 0 && primaryActions.length > 0
+ ? html`<div class="space"></div>`
+ : ''}
+ ${primaryActions.map(this.renderAction)}
+ ${this.renderOverflow(
+ [...overflowLinkItems, ...overflowActionItems],
+ disabledActions
+ )}
`;
}
@@ -1082,26 +1083,8 @@
>`;
}
- private renderActions() {
- const actions = this.actions ?? [];
- if (actions.length === 0) return;
- const primaryActions = actions.filter(a => a.primary).slice(0, 2);
- const overflowActions = actions.filter(a => !primaryActions.includes(a));
- return html`
- ${this.renderAction(primaryActions[0])}
- ${this.renderAction(primaryActions[1])}
- ${this.renderOverflowActions(overflowActions)}
- `;
- }
-
- private renderOverflowActions(overflowActions: Action[]) {
- const items = overflowActions.map(action => {
- return {...action, id: action.name};
- });
- if (!items || items.length === 0) return;
- const disabledItems = items
- .filter(action => action.disabled)
- .map(action => action.id);
+ private renderOverflow(items: DropdownLink[], disabledIds: string[] = []) {
+ if (items.length === 0) return;
return html`
<gr-dropdown
id="moreActions"
@@ -1110,7 +1093,7 @@
horizontal-align="right"
@tap-item="${this.handleAction}"
.items="${items}"
- .disabledIds="${disabledItems}"
+ .disabledIds="${disabledIds}"
>
<iron-icon icon="gr-icons:more-vert" aria-labelledby="moreMessage">
</iron-icon>
@@ -1120,7 +1103,7 @@
}
private handleAction(e: CustomEvent<Action>) {
- fireActionTriggered(this, e.detail);
+ this.checksService.triggerAction(e.detail);
}
private renderAction(action?: Action) {
@@ -1202,11 +1185,8 @@
);
const isSelection = this.selectedRuns.length > 0;
const selected = all.filter(result => this.isRunSelected(result));
- const filtered = selected.filter(
- result =>
- this.filterRegExp.test(result.checkName) ||
- this.filterRegExp.test(result.summary) ||
- this.filterRegExp.test(result.message ?? '')
+ const filtered = selected.filter(result =>
+ matches(result, this.filterRegExp)
);
let expanded = this.isSectionExpanded.get(category);
const expandedByUser = this.isSectionExpandedByUser.get(category) ?? false;
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
index 250b035..76fa353 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-runs.ts
@@ -14,25 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html, nothing} from 'lit-html';
-import {classMap} from 'lit-html/directives/class-map';
+import {classMap} from 'lit/directives/class-map';
import './gr-hovercard-run';
-import {
- css,
- customElement,
- property,
- PropertyValues,
- query,
- state,
-} from 'lit-element';
-import {GrLitElement} from '../lit/gr-lit-element';
+import {css, html, LitElement, nothing, PropertyValues} from 'lit';
+import {customElement, property, query, state} from 'lit/decorators';
import './gr-checks-attempt';
import {Action, Link, RunStatus} from '../../api/checks';
import {sharedStyles} from '../../styles/shared-styles';
import {
AttemptDetail,
compareByWorstCategory,
- fireActionTriggered,
+ headerForStatus,
iconFor,
iconForRun,
PRIMARY_STATUS_ACTIONS,
@@ -43,17 +35,15 @@
allRunsSelectedPatchset$,
CheckRun,
ChecksPatchset,
- errorMessageLatest$,
+ ErrorMessages,
+ errorMessagesLatest$,
fakeActions,
fakeLinks,
fakeRun0,
fakeRun1,
fakeRun2,
fakeRun3,
- fakeRun4_1,
- fakeRun4_2,
- fakeRun4_3,
- fakeRun4_4,
+ fakeRun4Att,
loginCallbackLatest$,
updateStateSetResults,
} from '../../services/checks/checks-model';
@@ -68,9 +58,11 @@
import {charsOnly} from '../../utils/string-util';
import {appContext} from '../../services/app-context';
import {KnownExperimentId} from '../../services/flags/flags';
+import {subscribe} from '../lit/subscription-controller';
+import {fontStyles} from '../../styles/gr-font-styles';
@customElement('gr-checks-run')
-export class GrChecksRun extends GrLitElement {
+export class GrChecksRun extends LitElement {
static override get styles() {
return [
sharedStyles,
@@ -92,6 +84,15 @@
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
+ flex-shrink: 1;
+ }
+ .middle {
+ /* extra space must go between middle and right */
+ flex-grow: 1;
+ white-space: nowrap;
+ }
+ .middle gr-checks-attempt {
+ margin-left: var(--spacing-s);
}
.name {
font-weight: var(--font-weight-bold);
@@ -151,6 +152,7 @@
Alternatively we could have set the vertical padding to 0, but
that would not have been a nice click target. */
margin: calc(0px - var(--spacing-s));
+ margin-left: var(--spacing-s);
}
.attemptDetails {
padding-bottom: var(--spacing-s);
@@ -244,6 +246,8 @@
<iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
${this.renderAdditionalIcon()}
<span class="name">${this.run.checkName}</span>
+ </div>
+ <div class="middle">
<gr-checks-attempt .run="${this.run}"></gr-checks-attempt>
${this.renderStatusLink()}
</div>
@@ -273,16 +277,20 @@
const checkNameId = charsOnly(this.run.checkName).toLowerCase();
const id = `attempt-${detail.attempt}`;
const icon = detail.icon;
+ const wasNotRun = icon === iconFor(RunStatus.RUNNABLE);
return html`<div class="attemptDetail">
<input
type="radio"
id="${id}"
name="${`${checkNameId}-attempt-choice`}"
?checked="${this.isSelected(detail)}"
+ ?disabled="${!this.isSelected(detail) && wasNotRun}"
@change="${() => this.handleAttemptChange(detail)}"
/>
<iron-icon class="${icon}" icon="gr-icons:${icon}"></iron-icon>
- <label for="${id}">Attempt ${detail.attempt}</label>
+ <label for="${id}">
+ Attempt ${detail.attempt}${wasNotRun ? ' (not run)' : ''}
+ </label>
</div>`;
}
@@ -295,9 +303,6 @@
renderStatusLink() {
const link = this.run.statusLink;
if (!link) return;
- // For COMPLETED we think that the status link are too much clutter.
- // That could be re-considered.
- if (this.run.status !== RunStatus.RUNNING) return;
return html`
<a href="${link}" target="_blank" @click="${this.onLinkClick}"
><iron-icon
@@ -353,7 +358,7 @@
}
@customElement('gr-checks-runs')
-export class GrChecksRuns extends GrLitElement {
+export class GrChecksRuns extends LitElement {
@query('#filterInput')
filterInput?: HTMLInputElement;
@@ -380,7 +385,7 @@
tabState?: ChecksTabState;
@property()
- errorMessage?: string;
+ errorMessages: ErrorMessages = {};
@property()
loginCallback?: () => void;
@@ -389,16 +394,19 @@
private flagService = appContext.flagsService;
+ private checksService = appContext.checksService;
+
constructor() {
super();
- this.subscribe('runs', allRunsSelectedPatchset$);
- this.subscribe('errorMessage', errorMessageLatest$);
- this.subscribe('loginCallback', loginCallbackLatest$);
+ subscribe(this, allRunsSelectedPatchset$, x => (this.runs = x));
+ subscribe(this, errorMessagesLatest$, x => (this.errorMessages = x));
+ subscribe(this, loginCallbackLatest$, x => (this.loginCallback = x));
}
static override get styles() {
return [
sharedStyles,
+ fontStyles,
css`
:host {
display: block;
@@ -469,6 +477,7 @@
padding: var(--spacing-m);
color: var(--primary-text-color);
margin-top: var(--spacing-m);
+ max-width: 400px;
}
.error {
display: flex;
@@ -522,7 +531,7 @@
<div class="flex-space"></div>
${this.renderTitleButtons()} ${this.renderCollapseButton()}
</h2>
- ${this.renderError()} ${this.renderSignIn()}
+ ${this.renderErrors()} ${this.renderSignIn()}
<input
id="filterInput"
type="text"
@@ -536,23 +545,26 @@
`;
}
- private renderError() {
- if (!this.errorMessage) return;
- return html`
- <div class="error">
- <div class="left">
- <iron-icon icon="gr-icons:error"></iron-icon>
- </div>
- <div class="right">
- <div>Error while fetching check results</div>
- <div>${this.errorMessage}</div>
- </div>
- </div>
- `;
+ private renderErrors() {
+ return Object.entries(this.errorMessages).map(
+ ([plugin, message]) =>
+ html`
+ <div class="error">
+ <div class="left">
+ <iron-icon icon="gr-icons:error"></iron-icon>
+ </div>
+ <div class="right">
+ <div class="message">
+ Error while fetching results for ${plugin}:<br />${message}
+ </div>
+ </div>
+ </div>
+ `
+ );
}
private renderSignIn() {
- if (this.errorMessage || !this.loginCallback) return;
+ if (!this.loginCallback) return;
return html`
<div class="login">
<div>
@@ -589,42 +601,48 @@
@click="${() => fireRunSelectionReset(this)}"
>Unselect All</gr-button
>
- <gr-button
- class="font-normal"
- link
+ <gr-tooltip-content
title="${runButtonDisabled
? 'Disabled. Unselect checks without a "Run" action to enable the button.'
: ''}"
- has-tooltip="${runButtonDisabled}"
- ?disabled="${runButtonDisabled}"
- @click="${() => {
- actions.forEach(action => fireActionTriggered(this, action));
- }}"
- >Run Selected</gr-button
+ ?has-tooltip=${runButtonDisabled}
>
+ <gr-button
+ class="font-normal"
+ link
+ ?disabled=${runButtonDisabled}
+ @click="${() => {
+ actions.forEach(action => this.checksService.triggerAction(action));
+ }}"
+ >Run Selected</gr-button
+ >
+ </gr-tooltip-content>
`;
}
private renderCollapseButton() {
return html`
- <gr-button
- link
- class="expandButton"
- role="switch"
- ?aria-checked="${this.collapsed}"
- aria-label="${this.collapsed
- ? 'Expand runs panel'
- : 'Collapse runs panel'}"
- has-tooltip="true"
+ <gr-tooltip-content
+ has-tooltip
title="${this.collapsed ? 'Expand runs panel' : 'Collapse runs panel'}"
- @click="${() => (this.collapsed = !this.collapsed)}"
- ><iron-icon
- class="expandIcon"
- icon="${this.collapsed
- ? 'gr-icons:chevron-right'
- : 'gr-icons:chevron-left'}"
- ></iron-icon>
- </gr-button>
+ >
+ <gr-button
+ link
+ class="expandButton"
+ role="switch"
+ ?aria-checked="${this.collapsed}"
+ aria-label="${this.collapsed
+ ? 'Expand runs panel'
+ : 'Collapse runs panel'}"
+ @click="${() => (this.collapsed = !this.collapsed)}"
+ ><iron-icon
+ class="expandIcon"
+ icon="${this.collapsed
+ ? 'gr-icons:chevron-right'
+ : 'gr-icons:chevron-left'}"
+ ></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>
`;
}
@@ -652,13 +670,7 @@
updateStateSetResults('f1', [fakeRun1], [], [], ChecksPatchset.LATEST);
updateStateSetResults('f2', [fakeRun2], [], [], ChecksPatchset.LATEST);
updateStateSetResults('f3', [fakeRun3], [], [], ChecksPatchset.LATEST);
- updateStateSetResults(
- 'f4',
- [fakeRun4_1, fakeRun4_2, fakeRun4_3, fakeRun4_4],
- [],
- [],
- ChecksPatchset.LATEST
- );
+ updateStateSetResults('f4', fakeRun4Att, [], [], ChecksPatchset.LATEST);
}
toggle(
@@ -694,7 +706,7 @@
@click="${() => this.toggleExpanded(status)}"
>
<iron-icon class="expandIcon" icon="${icon}"></iron-icon>
- <h3 class="heading-3">${status.toLowerCase()}</h3>
+ <h3 class="heading-3">${headerForStatus(status)}</h3>
</div>
<div class="sectionRuns">${runs.map(run => this.renderRun(run))}</div>
</div>
@@ -748,11 +760,7 @@
<gr-button link @click="${() => this.toggle('f3', [fakeRun3])}"
>3</gr-button
>
- <gr-button
- link
- @click="${() => {
- this.toggle('f4', [fakeRun4_1, fakeRun4_2, fakeRun4_3, fakeRun4_4]);
- }}"
+ <gr-button link @click="${() => this.toggle('f4', fakeRun4Att)}}"
>4</gr-button
>
<gr-button link @click="${this.all}">all</gr-button>
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-styles.ts b/polygerrit-ui/app/elements/checks/gr-checks-styles.ts
index 9a1605e..dbc2bec 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-styles.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-styles.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
index 1e98dfa..688667a 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-tab.ts
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {css, customElement, property, PropertyValues, state} from 'lit-element';
-import {GrLitElement} from '../lit/gr-lit-element';
+import {LitElement, css, html, PropertyValues} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
import {Action} from '../../api/checks';
import {
CheckResult,
@@ -32,17 +31,15 @@
import {ActionTriggeredEvent} from '../../services/checks/checks-util';
import {AttemptSelectedEvent, RunSelectedEvent} from './gr-checks-util';
import {ChecksTabState} from '../../types/events';
-import {fireAlert, fireEvent} from '../../utils/event-util';
import {appContext} from '../../services/app-context';
-import {from, timer} from 'rxjs';
-import {takeUntil} from 'rxjs/operators';
+import {subscribe} from '../lit/subscription-controller';
/**
* The "Checks" tab on the Gerrit change page. Gets its data from plugins that
* have registered with the Checks Plugin API.
*/
@customElement('gr-checks-tab')
-export class GrChecksTab extends GrLitElement {
+export class GrChecksTab extends LitElement {
@property()
runs: CheckRun[] = [];
@@ -75,11 +72,15 @@
constructor() {
super();
- this.subscribe('runs', allRunsSelectedPatchset$);
- this.subscribe('results', allResultsSelected$);
- this.subscribe('checksPatchsetNumber', checksSelectedPatchsetNumber$);
- this.subscribe('latestPatchsetNumber', latestPatchNum$);
- this.subscribe('changeNum', changeNum$);
+ subscribe(this, allRunsSelectedPatchset$, x => (this.runs = x));
+ subscribe(this, allResultsSelected$, x => (this.results = x));
+ subscribe(
+ this,
+ checksSelectedPatchsetNumber$,
+ x => (this.checksPatchsetNumber = x)
+ );
+ subscribe(this, latestPatchNum$, x => (this.latestPatchsetNumber = x));
+ subscribe(this, changeNum$, x => (this.changeNum = x));
this.addEventListener('action-triggered', (e: ActionTriggeredEvent) =>
this.handleActionTriggered(e.detail.action, e.detail.run)
@@ -139,35 +140,7 @@
}
handleActionTriggered(action: Action, run?: CheckRun) {
- if (!this.changeNum) return;
- const patchSet = this.checksPatchsetNumber ?? this.latestPatchsetNumber;
- if (!patchSet) return;
- const promise = action.callback(
- this.changeNum,
- patchSet,
- run?.attempt,
- run?.externalId,
- run?.checkName,
- action.name
- );
- // If plugins return undefined or not a promise, then show no toast.
- if (!promise?.then) return;
-
- fireAlert(this, `Triggering action '${action.name}' ...`);
- from(promise)
- // If the action takes longer than 5 seconds, then most likely the
- // user is either not interested or the result not relevant anymore.
- .pipe(takeUntil(timer(5000)))
- .subscribe(result => {
- if (result.errorMessage || result.message) {
- fireAlert(this, `${result.message ?? result.errorMessage}`);
- } else {
- fireEvent(this, 'hide-alert');
- }
- if (result.shouldReload) {
- this.checksService.reloadForCheck(run?.checkName);
- }
- });
+ this.checksService.triggerAction(action, run);
}
handleRunSelected(e: RunSelectedEvent) {
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util.ts b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
index 05a87a4..e9bbb22 100644
--- a/polygerrit-ui/app/elements/checks/gr-checks-util.ts
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {CheckRun} from '../../services/checks/checks-model';
+import {CheckRun, RunResult} from '../../services/checks/checks-model';
export interface AttemptSelectedEventDetail {
checkName: string;
@@ -85,3 +85,12 @@
(selected === undefined && run.isLatestAttempt) || selected === run.attempt
);
}
+
+export function matches(result: RunResult, regExp: RegExp) {
+ return (
+ regExp.test(result.checkName) ||
+ regExp.test(result.summary) ||
+ (result.tags ?? []).some(tag => regExp.test(tag.name)) ||
+ regExp.test(result.message ?? '')
+ );
+}
diff --git a/polygerrit-ui/app/elements/checks/gr-checks-util_test.ts b/polygerrit-ui/app/elements/checks/gr-checks-util_test.ts
new file mode 100644
index 0000000..698a4a1
--- /dev/null
+++ b/polygerrit-ui/app/elements/checks/gr-checks-util_test.ts
@@ -0,0 +1,34 @@
+/**
+ * @license
+ * 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.
+ */
+import '../../test/common-test-setup-karma';
+import {createRunResult} from '../../test/test-data-generators';
+import {matches} from './gr-checks-util';
+import {RunResult} from '../../services/checks/checks-model';
+
+suite('gr-checks-util test', () => {
+ test('regexp filter matching results', () => {
+ const result: RunResult = {
+ ...createRunResult(),
+ tags: [{name: 'tag'}],
+ };
+ assert.isTrue(matches(result, new RegExp('message')));
+ assert.isTrue(matches(result, new RegExp('summary')));
+ assert.isTrue(matches(result, new RegExp('name')));
+ assert.isTrue(matches(result, new RegExp('tag')));
+ assert.isFalse(matches(result, new RegExp('qwertyui')));
+ });
+});
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
index 2316a05..d26856c 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run.ts
@@ -15,13 +15,15 @@
* limitations under the License.
*/
import './gr-checks-styles';
-import {hovercardBehaviorMixin} from '../shared/gr-hovercard/gr-hovercard-behavior';
+import '../../styles/gr-font-styles';
+import {HovercardBehaviorMixin} from '../shared/gr-hovercard/gr-hovercard-behavior';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard-run_html';
import {customElement, property} from '@polymer/decorators';
import './gr-checks-action';
import {CheckRun} from '../../services/checks/checks-model';
import {
+ AttemptDetail,
iconFor,
runActions,
worstCategory,
@@ -30,8 +32,11 @@
import {RunStatus} from '../../api/checks';
import {ordinal} from '../../utils/string-util';
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = HovercardBehaviorMixin(PolymerElement);
+
@customElement('gr-hovercard-run')
-export class GrHovercardRun extends hovercardBehaviorMixin(PolymerElement) {
+export class GrHovercardRun extends base {
static get template() {
return htmlTemplate;
}
@@ -56,6 +61,13 @@
return ordinal(attempt);
}
+ computeAttempts(run?: CheckRun): AttemptDetail[] {
+ const details = run?.attemptDetails ?? [];
+ const more =
+ details.length > 7 ? [{icon: 'more-horiz', attempt: undefined}] : [];
+ return [...more, ...details.slice(-7)];
+ }
+
computeChipIcon(run?: CheckRun) {
if (run?.status === RunStatus.COMPLETED) return 'check';
if (run?.status === RunStatus.RUNNING) return 'timelapse';
diff --git a/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
index 5b2e24a..49a1416 100644
--- a/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
+++ b/polygerrit-ui/app/elements/checks/gr-hovercard-run_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-checks-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
@@ -30,6 +33,9 @@
display: flex;
margin-top: var(--spacing-s);
}
+ .attempts.row {
+ flex-wrap: wrap;
+ }
.chipRow {
display: flex;
margin-top: var(--spacing-s);
@@ -91,7 +97,7 @@
margin-right: var(--spacing-s);
color: var(--deemphasized-text-color);
text-align: center;
- width: 20px;
+ width: 24px;
font-size: var(--font-size-small);
}
div.action {
@@ -151,9 +157,9 @@
<iron-icon class="small" icon="gr-icons:arrow-forward"></iron-icon>
</div>
<div class="sectionContent">
- <div hidden$="[[hideAttempts(run)]]" class="row">
+ <div hidden$="[[hideAttempts(run)]]" class="attempts row">
<div class="title">Attempt</div>
- <template is="dom-repeat" items="[[run.attemptDetails]]">
+ <template is="dom-repeat" items="[[computeAttempts(run)]]">
<div>
<div class="attemptIcon">
<iron-icon
@@ -216,7 +222,10 @@
</div>
<template is="dom-repeat" items="[[computeActions(run)]]">
<div class="action">
- <gr-checks-action action="[[item]]"></gr-checks-action>
+ <gr-checks-action
+ event-target="[[_target]]"
+ action="[[item]]"
+ ></gr-checks-action>
</div>
</template>
</div>
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
index 881eb28..c2066d7 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
@@ -25,8 +25,8 @@
DropdownLink,
} from '../../shared/gr-dropdown/gr-dropdown';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
const INTERPOLATE_URL_PATTERN = /\${([\w]+)}/g;
@@ -37,7 +37,7 @@
}
@customElement('gr-account-dropdown')
-export class GrAccountDropdown extends GrLitElement {
+export class GrAccountDropdown extends LitElement {
@property({type: Object})
account?: AccountInfo;
@@ -76,7 +76,7 @@
super.disconnectedCallback();
}
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -92,9 +92,10 @@
];
}
- render() {
+ override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
gr-dropdown {
@@ -111,17 +112,17 @@
<gr-dropdown
link=""
.items="${this.links}"
- .top-content="${this.topContent}"
+ .topContent="${this.topContent}"
@tap-item-shortcuts=${this._handleShortcutsTap}
- .horizontal-align="right"
+ .horizontalAlign=${'right'}
>
- <span ?hidden=${this._hasAvatars}
+ <span ?hidden="${this._hasAvatars}"
>${this._accountName(this.account)}</span
>
<gr-avatar
.account="${this.account}"
?hidden=${!this._hasAvatars}
- .imageSize="56"
+ .imageSize=${56}
aria-label="Account avatar"
></gr-avatar>
</gr-dropdown>`;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.ts
index 3ccc960..80ebf2d 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.ts
@@ -30,6 +30,7 @@
} from '../../../test/test-data-generators';
import {tap} from '@polymer/iron-test-helpers/mock-interactions';
import {AccountId} from '../../../types/common';
+import {waitUntil} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-error-manager');
@@ -62,7 +63,7 @@
});
});
- test('does not show auth error on 403 by default', done => {
+ test('does not show auth error on 403 by default', async () => {
const showAuthErrorStub = sinon.stub(element, '_showAuthErrorAlert');
const responseText = Promise.resolve('server says no.');
element.dispatchEvent(
@@ -79,13 +80,11 @@
bubbles: true,
})
);
- flush(() => {
- assert.isFalse(showAuthErrorStub.calledOnce);
- done();
- });
+ await flush();
+ assert.isFalse(showAuthErrorStub.calledOnce);
});
- test('show auth required for 403 with auth error and not authed before', done => {
+ test('show auth required for 403 with auth error and not authed before', async () => {
const showAuthErrorStub = sinon.stub(element, '_showAuthErrorAlert');
const responseText = Promise.resolve('Authentication required\n');
getLoggedInStub.returns(Promise.resolve(true));
@@ -103,10 +102,8 @@
bubbles: true,
})
);
- flush(() => {
- assert.isTrue(showAuthErrorStub.calledOnce);
- done();
- });
+ await flush();
+ assert.isTrue(showAuthErrorStub.calledOnce);
});
test('recheck auth for 403 with auth error if authed before', async () => {
@@ -148,7 +145,7 @@
);
});
- test('show normal Error', done => {
+ test('show normal Error', async () => {
const showErrorSpy = sinon.spy(element, '_showErrorDialog');
const textSpy = sinon.spy(() => Promise.resolve('ZOMG'));
element.dispatchEvent(
@@ -160,13 +157,9 @@
);
assert.isTrue(textSpy.called);
- flush(() => {
- assert.isTrue(showErrorSpy.calledOnce);
- assert.isTrue(
- showErrorSpy.lastCall.calledWithExactly('Error 500: ZOMG')
- );
- done();
- });
+ await flush();
+ assert.isTrue(showErrorSpy.calledOnce);
+ assert.isTrue(showErrorSpy.lastCall.calledWithExactly('Error 500: ZOMG'));
});
test('constructServerErrorMsg', () => {
@@ -206,7 +199,7 @@
);
});
- test('extract trace id from headers if exists', done => {
+ test('extract trace id from headers if exists', async () => {
const textSpy = sinon.spy(() => Promise.resolve('500'));
const headers = new Headers();
headers.set('X-Gerrit-Trace', 'xxxx');
@@ -223,16 +216,14 @@
bubbles: true,
})
);
- flush(() => {
- assert.equal(
- element.$.errorDialog.text,
- 'Error 500: 500\nTrace Id: xxxx'
- );
- done();
- });
+ await flush();
+ assert.equal(
+ element.$.errorDialog.text,
+ 'Error 500: 500\nTrace Id: xxxx'
+ );
});
- test('suppress TOO_MANY_FILES error', done => {
+ test('suppress TOO_MANY_FILES error', async () => {
const showAlertStub = sinon.stub(element, '_showAlert');
const textSpy = sinon.spy(() =>
Promise.resolve('too many files to find conflicts')
@@ -246,13 +237,11 @@
);
assert.isTrue(textSpy.called);
- flush(() => {
- assert.isFalse(showAlertStub.called);
- done();
- });
+ await flush();
+ assert.isFalse(showAlertStub.called);
});
- test('suppress CONFLICTS_OPERATOR_IS_NOT_SUPPORTED error', done => {
+ test('suppress CONFLICTS_OPERATOR_IS_NOT_SUPPORTED error', async () => {
const showAlertStub = sinon.stub(element, '_showAlert');
const textSpy = sinon.spy(() =>
Promise.resolve("'conflicts:' operator is not supported by server")
@@ -266,13 +255,11 @@
);
assert.isTrue(textSpy.called);
- flush(() => {
- assert.isFalse(showAlertStub.called);
- done();
- });
+ await flush();
+ assert.isFalse(showAlertStub.called);
});
- test('show network error', done => {
+ test('show network error', async () => {
const showAlertStub = sinon.stub(element, '_showAlert');
element.dispatchEvent(
new CustomEvent('network-error', {
@@ -281,13 +268,11 @@
bubbles: true,
})
);
- flush(() => {
- assert.isTrue(showAlertStub.calledOnce);
- assert.isTrue(
- showAlertStub.lastCall.calledWithExactly('Server unavailable')
- );
- done();
- });
+ await flush();
+ assert.isTrue(showAlertStub.calledOnce);
+ assert.isTrue(
+ showAlertStub.lastCall.calledWithExactly('Server unavailable')
+ );
});
test('_canOverride alerts', () => {
@@ -487,7 +472,7 @@
assert.include(toast.shadowRoot.textContent, 'second-test');
});
- test('regular toast should not dismiss auth toast', done => {
+ test('regular toast should not dismiss auth toast', async () => {
// Set status to AUTHED.
appContext.authService.authCheck();
const responseText = Promise.resolve('Authentication required\n');
@@ -509,37 +494,34 @@
})
);
assert.equal(fetchStub.callCount, 1);
- flush(() => {
- // here needs two flush as there are two chained
- // promises on server-error handler and flush only flushes one
- assert.equal(fetchStub.callCount, 2);
- flush(() => {
- let toast = toastSpy.lastCall.returnValue;
- assert.include(toast.shadowRoot.textContent, 'Credentials expired.');
- assert.include(toast.shadowRoot.textContent, 'Refresh credentials');
+ await flush();
- // fake an alert
- element.dispatchEvent(
- new CustomEvent('show-alert', {
- detail: {
- message: 'test-alert',
- action: 'reload',
- },
- composed: true,
- bubbles: true,
- })
- );
- flush(() => {
- toast = toastSpy.lastCall.returnValue;
- assert.isOk(toast);
- assert.include(
- toast.shadowRoot.textContent,
- 'Credentials expired.'
- );
- done();
- });
- });
- });
+ // here needs two flush as there are two chained
+ // promises on server-error handler and flush only flushes one
+ assert.equal(fetchStub.callCount, 2);
+ await flush();
+ await waitUntil(() => toastSpy.calledOnce);
+ let toast = toastSpy.lastCall.returnValue;
+ assert.include(toast.shadowRoot.textContent, 'Credentials expired.');
+ assert.include(toast.shadowRoot.textContent, 'Refresh credentials');
+
+ // fake an alert
+ element.dispatchEvent(
+ new CustomEvent('show-alert', {
+ detail: {
+ message: 'test-alert',
+ action: 'reload',
+ },
+ composed: true,
+ bubbles: true,
+ })
+ );
+
+ await flush();
+ assert.isTrue(toastSpy.calledOnce);
+ toast = toastSpy.lastCall.returnValue;
+ assert.isOk(toast);
+ assert.include(toast.shadowRoot.textContent, 'Credentials expired.');
});
test('show alert', () => {
@@ -578,7 +560,7 @@
assert.equal(element._lastCredentialCheck, 999999);
});
- test('refreshes with same credentials', done => {
+ test('refreshes with same credentials', async () => {
const accountPromise = Promise.resolve({
...createAccountDetailWithId(1234),
});
@@ -594,12 +576,10 @@
element._refreshingCredentials = true;
element._checkSignedIn();
- flush(() => {
- assert.isFalse(requestCheckStub.called);
- assert.isTrue(handleRefreshStub.called);
- assert.isFalse(reloadStub.called);
- done();
- });
+ await flush();
+ assert.isFalse(requestCheckStub.called);
+ assert.isTrue(handleRefreshStub.called);
+ assert.isFalse(reloadStub.called);
});
test('_showAlert hides existing alerts', () => {
@@ -609,7 +589,7 @@
// assert.isTrue(hideStub.calledOnce);
});
- test('show-error', () => {
+ test('show-error', async () => {
const openStub = sinon.stub(element.$.errorOverlay, 'open');
const closeStub = sinon.stub(element.$.errorOverlay, 'close');
const reportStub = stubReporting('reportErrorDialog');
@@ -622,7 +602,7 @@
bubbles: true,
})
);
- flush();
+ await flush();
assert.isTrue(openStub.called);
assert.isTrue(reportStub.called);
@@ -634,12 +614,12 @@
bubbles: true,
})
);
- flush();
+ await flush();
assert.isTrue(closeStub.called);
});
- test('reloads when refreshed credentials differ', done => {
+ test('reloads when refreshed credentials differ', async () => {
const accountPromise = Promise.resolve({
...createAccountDetailWithId(1234),
});
@@ -655,12 +635,11 @@
element._refreshingCredentials = true;
element._checkSignedIn();
- flush(() => {
- assert.isFalse(requestCheckStub.called);
- assert.isFalse(handleRefreshStub.called);
- assert.isTrue(reloadStub.called);
- done();
- });
+ await flush();
+
+ assert.isFalse(requestCheckStub.called);
+ assert.isFalse(handleRefreshStub.called);
+ assert.isTrue(reloadStub.called);
});
});
@@ -678,7 +657,7 @@
});
});
- test('refresh loop continues on credential fail', done => {
+ test('refresh loop continues on credential fail', async () => {
const requestCheckStub = sinon.stub(element, '_requestCheckLoggedIn');
const handleRefreshStub = sinon.stub(
element,
@@ -689,12 +668,10 @@
element._refreshingCredentials = true;
element._checkSignedIn();
- flush(() => {
- assert.isTrue(requestCheckStub.called);
- assert.isFalse(handleRefreshStub.called);
- assert.isFalse(reloadStub.called);
- done();
- });
+ await flush();
+ assert.isTrue(requestCheckStub.called);
+ assert.isFalse(handleRefreshStub.called);
+ assert.isFalse(reloadStub.called);
});
});
});
diff --git a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
index c820ec4..1ae0992 100644
--- a/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
+++ b/polygerrit-ui/app/elements/core/gr-key-binding-display/gr-key-binding-display.ts
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {html} from 'lit-html';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -25,7 +24,7 @@
}
@customElement('gr-key-binding-display')
-export class GrKeyBindingDisplay extends GrLitElement {
+export class GrKeyBindingDisplay extends LitElement {
static override get styles() {
return [
css`
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
index 68b696e..0b191f1 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog.ts
@@ -17,6 +17,7 @@
import '../../shared/gr-button/gr-button';
import '../gr-key-binding-display/gr-key-binding-display';
import '../../../styles/shared-styles';
+import '../../../styles/gr-font-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-keyboard-shortcuts-dialog_html';
import {
@@ -38,10 +39,11 @@
shortcuts?: SectionView;
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-keyboard-shortcuts-dialog')
-export class GrKeyboardShortcutsDialog extends KeyboardShortcutMixin(
- PolymerElement
-) {
+export class GrKeyboardShortcutsDialog extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
index 3576dfe..4992daa 100644
--- a/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-keyboard-shortcuts-dialog/gr-keyboard-shortcuts-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
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 4bd048c..b745c3d 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
@@ -210,17 +210,19 @@
class="hideOnMobile"
name="header-browse-source"
></gr-endpoint-decorator>
- <template is="dom-if" if="[[_feedbackURL]]">
- <a class="feedbackButton"
- href$="[[_feedbackURL]]"
- title="File a bug"
- aria-label="File a bug"
- target="_blank"
- role="button"
- >
- <iron-icon icon="gr-icons:bug"></iron-icon>
- </a>
- </template>
+ <gr-endpoint-decorator class="feedbackButton" name="header-feedback">
+ <template is="dom-if" if="[[_feedbackURL]]">
+ <a
+ href$="[[_feedbackURL]]"
+ title="File a bug"
+ aria-label="File a bug"
+ target="_blank"
+ role="button"
+ >
+ <iron-icon icon="gr-icons:bug"></iron-icon>
+ </a>
+ </template>
+ </gr-endpoint-decorator>
</div>
<div class="accountContainer" id="accountContainer">
<iron-icon
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
index 784b440..0f58ac0 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.ts
@@ -474,7 +474,7 @@
test('shows feedback icon when URL provided', async () => {
assert.isEmpty(element._feedbackURL);
- assert.isNotOk(query(element, '.feedbackButton'));
+ assert.isNotOk(query(element, '.feedbackButton > a'));
const url = 'report_bug_url';
const config: ServerInfo = {
@@ -488,7 +488,7 @@
await flush();
assert.equal(element._feedbackURL, url);
- assert.ok(query(element, '.feedbackButton'));
+ assert.ok(query(element, '.feedbackButton > a'));
});
test('register URL', () => {
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
index 89e81d4..b8f2630 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
@@ -309,8 +309,8 @@
changeNum: NumericChangeId;
project: RepoName;
path?: string;
- patchNum?: PatchSetNum | null;
- basePatchNum?: BasePatchSetNum | null;
+ patchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
lineNum?: number | string;
leftSide?: boolean;
commentId?: UrlEncodedCommentId;
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index ac4ac64..8e70eb9 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -57,6 +57,7 @@
RepoName,
ServerInfo,
UrlEncodedCommentId,
+ ParentPatchSetNum,
} from '../../../types/common';
import {
AppElement,
@@ -176,8 +177,8 @@
CHANGE_ID_QUERY: /^\/id\/(I[0-9a-f]{40})$/,
- // Matches /c/<changeNum>/[<basePatchNum>..][<patchNum>][/].
- CHANGE_LEGACY: /^\/c\/(\d+)\/?(((-?\d+|edit)(\.\.(\d+|edit))?))?\/?$/,
+ // Matches /c/<changeNum>/[*][/].
+ CHANGE_LEGACY: /^\/c\/(\d+)\/(.*)$/,
CHANGE_NUMBER_LEGACY: /^\/(\d+)\/?/,
// Matches
@@ -209,10 +210,6 @@
// Matches /c/<project>/+/<changeNum>/[<patchNum|edit>]/<path>,edit[#lineNum]
DIFF_EDIT: /^\/c\/(.+)\/\+\/(\d+)\/(\d+|edit)\/(.+),edit(#\d+)?$/,
- // Matches non-project-relative
- // /c/<changeNum>/[<basePatchNum>..]<patchNum>/<path>.
- DIFF_LEGACY: /^\/c\/(\d+)\/((-?\d+|edit)(\.\.(\d+|edit))?)\/(.+)/,
-
// Matches diff routes using @\d+ to specify a file name (whether or not
// the project name is included).
// eslint-disable-next-line max-len
@@ -286,18 +283,9 @@
type QueryStringItem = [string, string]; // [key, value]
-type GenerateUrlLegacyChangeViewParameters = Omit<
- GenerateUrlChangeViewParameters,
- 'project'
->;
-type GenerateUrlLegacyDiffViewParameters = Omit<
- GenerateUrlDiffViewParameters,
- 'project'
->;
-
interface PatchRangeParams {
- patchNum?: PatchSetNum | null;
- basePatchNum?: BasePatchSetNum | null;
+ patchNum?: PatchSetNum;
+ basePatchNum?: BasePatchSetNum;
}
@customElement('gr-router')
@@ -671,66 +659,34 @@
if (params.patchNum) {
range = `${params.patchNum}`;
}
- if (params.basePatchNum) {
+ if (params.basePatchNum && params.basePatchNum !== ParentPatchSetNum) {
range = `${params.basePatchNum}..${range}`;
}
return range;
}
/**
- * Given a set of params without a project, gets the project from the rest
- * API project lookup and then sets the app params.
- */
- _normalizeLegacyRouteParams(
- params: Readonly<
- | GenerateUrlLegacyChangeViewParameters
- | GenerateUrlLegacyDiffViewParameters
- >
- ) {
- if (!params.changeNum) {
- return Promise.resolve();
- }
-
- return this.restApiService
- .getFromProjectLookup(params.changeNum)
- .then(project => {
- // Show a 404 and terminate if the lookup request failed. Attempting
- // to redirect after failing to get the project loops infinitely.
- if (!project) {
- this._show404();
- return;
- }
- const updatedParams:
- | GenerateUrlChangeViewParameters
- | GenerateUrlDiffViewParameters = {...params, project};
- this._normalizePatchRangeParams(updatedParams);
- this._redirect(this._generateUrl(updatedParams));
- });
- }
-
- /**
* Normalizes the params object, and determines if the URL needs to be
* modified to fit the proper schema.
*
*/
_normalizePatchRangeParams(params: PatchRangeParams) {
- if (params.basePatchNum === null || params.basePatchNum === undefined) {
+ if (params.basePatchNum === undefined) {
return false;
}
- const hasPatchNum =
- params.patchNum !== null && params.patchNum !== undefined;
+ const hasPatchNum = params.patchNum !== undefined;
let needsRedirect = false;
// Diffing a patch against itself is invalid, so if the base and revision
// patches are equal clear the base.
if (params.patchNum && params.basePatchNum === params.patchNum) {
needsRedirect = true;
- params.basePatchNum = null;
+ params.basePatchNum = ParentPatchSetNum;
} else if (!hasPatchNum) {
// Regexes set basePatchNum instead of patchNum when only one is
// specified. Redirect is not needed in this case.
params.patchNum = params.basePatchNum;
- params.basePatchNum = null;
+ params.basePatchNum = ParentPatchSetNum;
}
return needsRedirect;
}
@@ -1100,8 +1056,6 @@
this._mapRoute(RoutePattern.CHANGE_LEGACY, '_handleChangeLegacyRoute');
- this._mapRoute(RoutePattern.DIFF_LEGACY, '_handleDiffLegacyRoute');
-
this._mapRoute(RoutePattern.AGREEMENTS, '_handleAgreementsRoute', true);
this._mapRoute(
@@ -1666,41 +1620,26 @@
}
_handleChangeLegacyRoute(ctx: PageContextWithQueryMap) {
- // Parameter order is based on the regex group number matched.
- const params: GenerateUrlLegacyChangeViewParameters = {
- changeNum: Number(ctx.params[0]) as NumericChangeId,
- basePatchNum: convertToPatchSetNum(ctx.params[3]) as BasePatchSetNum,
- patchNum: convertToPatchSetNum(ctx.params[5]),
- view: GerritView.CHANGE,
- querystring: ctx.querystring,
- };
-
- this._normalizeLegacyRouteParams(params);
+ const changeNum = Number(ctx.params[0]) as NumericChangeId;
+ if (!changeNum) {
+ this._show404();
+ return;
+ }
+ this.restApiService.getFromProjectLookup(changeNum).then(project => {
+ // Show a 404 and terminate if the lookup request failed. Attempting
+ // to redirect after failing to get the project loops infinitely.
+ if (!project) {
+ this._show404();
+ return;
+ }
+ this._redirect(`/c/${project}/+/${changeNum}/${ctx.params[1]}`);
+ });
}
_handleLegacyLinenum(ctx: PageContextWithQueryMap) {
this._redirect(ctx.path.replace(LEGACY_LINENUM_PATTERN, '#$1'));
}
- _handleDiffLegacyRoute(ctx: PageContextWithQueryMap) {
- // Parameter order is based on the regex group number matched.
- const params: GenerateUrlLegacyDiffViewParameters = {
- changeNum: Number(ctx.params[0]) as NumericChangeId,
- basePatchNum: convertToPatchSetNum(ctx.params[2]) as BasePatchSetNum,
- patchNum: convertToPatchSetNum(ctx.params[4]),
- path: ctx.params[5],
- view: GerritView.DIFF,
- };
-
- const address = this._parseLineAddress(ctx.hash);
- if (address) {
- params.leftSide = address.leftSide;
- params.lineNum = address.lineNum;
- }
-
- this._normalizeLegacyRouteParams(params);
- }
-
_handleDiffEditRoute(ctx: PageContextWithQueryMap) {
// Parameter order is based on the regex group number matched.
const project = ctx.params[0] as RepoName;
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
index ff27bbd..b91bf0c 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
@@ -22,6 +22,7 @@
import {stubBaseUrl, stubRestApi, addListenerForTest} from '../../../test/test-utils.js';
import {_testOnly_RoutePattern} from './gr-router.js';
import {GerritView} from '../../../services/router/router-model.js';
+import {ParentPatchSetNum} from '../../../types/common.js';
const basicFixture = fixtureFromElement('gr-router');
@@ -191,7 +192,6 @@
'_handleDiffRoute',
'_handleDefaultRoute',
'_handleChangeLegacyRoute',
- '_handleDiffLegacyRoute',
'_handleDocumentationRedirectRoute',
'_handleDocumentationSearchRoute',
'_handleDocumentationSearchRedirectRoute',
@@ -535,72 +535,12 @@
});
suite('param normalization', () => {
- let projectLookupStub;
- let generateUrlStub;
-
- setup(() => {
- projectLookupStub = stubRestApi('getFromProjectLookup');
- generateUrlStub = sinon.stub(element, '_generateUrl');
- });
-
- suite('_normalizeLegacyRouteParams', () => {
- let rangeStub;
- let redirectStub;
- let show404Stub;
-
- setup(() => {
- rangeStub = sinon.stub(element, '_normalizePatchRangeParams')
- .returns(Promise.resolve());
- redirectStub = sinon.stub(element, '_redirect');
- show404Stub = sinon.stub(element, '_show404');
- });
-
- test('w/o changeNum', () => {
- projectLookupStub.returns(Promise.resolve('foo/bar'));
- const params = {};
- return element._normalizeLegacyRouteParams(params).then(() => {
- assert.isFalse(generateUrlStub.calledOnce);
- assert.isFalse(projectLookupStub.called);
- assert.isFalse(rangeStub.called);
- assert.isFalse(redirectStub.called);
- assert.isFalse(show404Stub.called);
- });
- });
-
- test('w/ changeNum', () => {
- projectLookupStub.returns(Promise.resolve('foo/bar'));
- const params = {changeNum: 1234};
-
- return element._normalizeLegacyRouteParams(params).then(() => {
- assert.isTrue(generateUrlStub.calledOnce);
- const updatedParams = generateUrlStub.lastCall.args[0];
- assert.isTrue(projectLookupStub.called);
- assert.isTrue(rangeStub.called);
- assert.equal(updatedParams.project, 'foo/bar');
- assert.isTrue(redirectStub.calledOnce);
- assert.isFalse(show404Stub.called);
- });
- });
-
- test('halts on project lookup failure', () => {
- projectLookupStub.returns(Promise.resolve(undefined));
- const params = {changeNum: 1234};
- return element._normalizeLegacyRouteParams(params).then(() => {
- assert.isFalse(generateUrlStub.calledOnce);
- assert.isTrue(projectLookupStub.called);
- assert.isFalse(rangeStub.called);
- assert.isFalse(redirectStub.called);
- assert.isTrue(show404Stub.calledOnce);
- });
- });
- });
-
suite('_normalizePatchRangeParams', () => {
test('range n..n normalizes to n', () => {
const params = {basePatchNum: 4, patchNum: 4};
const needsRedirect = element._normalizePatchRangeParams(params);
assert.isTrue(needsRedirect);
- assert.isNotOk(params.basePatchNum);
+ assert.equal(params.basePatchNum, ParentPatchSetNum);
assert.equal(params.patchNum, 4);
});
@@ -608,7 +548,7 @@
const params = {basePatchNum: 4};
const needsRedirect = element._normalizePatchRangeParams(params);
assert.isFalse(needsRedirect);
- assert.isNotOk(params.basePatchNum);
+ assert.equal(params.basePatchNum, ParentPatchSetNum);
assert.equal(params.patchNum, 4);
});
});
@@ -1366,58 +1306,19 @@
assert.isTrue(redirectStub.calledWithExactly('/c/12345'));
});
- test('_handleChangeLegacyRoute', () => {
- const normalizeRouteStub = sinon.stub(element,
- '_normalizeLegacyRouteParams');
+ test('_handleChangeLegacyRoute', async () => {
+ stubRestApi('getFromProjectLookup').returns(Promise.resolve('project'));
const ctx = {
params: [
1234, // 0 Change number
- null, // 1 Unused
- null, // 2 Unused
- 6, // 3 Base patch number
- null, // 4 Unused
- 9, // 5 Patch number
+ 'comment/6789',
],
querystring: '',
};
element._handleChangeLegacyRoute(ctx);
- assert.isTrue(normalizeRouteStub.calledOnce);
- assert.deepEqual(normalizeRouteStub.lastCall.args[0], {
- changeNum: 1234,
- basePatchNum: 6,
- patchNum: 9,
- view: GerritView.CHANGE,
- querystring: '',
- });
- });
-
- test('_handleDiffLegacyRoute', () => {
- const normalizeRouteStub = sinon.stub(element,
- '_normalizeLegacyRouteParams');
- const ctx = {
- params: [
- 1234, // 0 Change number
- null, // 1 Unused
- 3, // 2 Base patch number
- null, // 3 Unused
- 8, // 4 Patch number
- 'foo/bar', // 5 Diff path
- ],
- path: '/c/1234/3..8/foo/bar',
- hash: 'b123',
- };
- element._handleDiffLegacyRoute(ctx);
- assert.isFalse(redirectStub.called);
- assert.isTrue(normalizeRouteStub.calledOnce);
- assert.deepEqual(normalizeRouteStub.lastCall.args[0], {
- changeNum: 1234,
- basePatchNum: 3,
- patchNum: 8,
- view: GerritView.DIFF,
- path: 'foo/bar',
- lineNum: 123,
- leftSide: true,
- });
+ await flush();
+ assert.isTrue(redirectStub.calledWithExactly('/c/project/+/1234' +
+ '/comment/6789'));
});
test('_handleLegacyLinenum w/ @321', () => {
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index 7c65c3f..240bb22 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -67,10 +67,10 @@
'footer:',
'from:',
'has:',
+ 'has:attention',
'has:draft',
'has:edit',
'has:star',
- 'has:stars',
'has:unresolved',
'hashtag:',
'inhashtag:',
@@ -78,6 +78,8 @@
'is:',
'is:abandoned',
'is:assigned',
+ 'is:attention',
+ 'is:cherrypick',
'is:closed',
'is:ignored',
'is:merge',
@@ -110,6 +112,7 @@
'reviewer:',
'reviewer:self',
'reviewerin:',
+ 'rule:',
'size:',
'star:',
'status:',
@@ -147,8 +150,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-search-bar')
-export class GrSearchBar extends KeyboardShortcutMixin(PolymerElement) {
+export class GrSearchBar extends base {
static get template() {
return htmlTemplate;
}
@@ -198,7 +204,7 @@
this.query = (input: string) => this._getSearchSuggestions(input);
}
- connectedCallback() {
+ override connectedCallback() {
super.connectedCallback();
this.restApiService.getConfig().then((serverConfig?: ServerInfo) => {
const mergeability =
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.ts
index 3b22d1d..b5b0124 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_test.ts
@@ -22,6 +22,7 @@
import {
TestKeyboardShortcutBinder,
stubRestApi,
+ mockPromise,
} from '../../../test/test-utils';
import {Shortcut} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {_testOnly_clearDocsBaseUrlCache} from '../../../utils/url-util';
@@ -47,9 +48,9 @@
TestKeyboardShortcutBinder.pop();
});
- setup(done => {
+ setup(async () => {
element = basicFixture.instantiate();
- flush(done);
+ await flush();
});
test('value is propagated to _inputVal', () => {
@@ -62,10 +63,11 @@
? document.activeElement!.shadowRoot.activeElement
: document.activeElement;
- test('enter in search input fires event', done => {
+ test('enter in search input fires event', async () => {
+ const promise = mockPromise();
element.addEventListener('handle-search', () => {
assert.notEqual(getActiveElement(), element.$.searchInput);
- done();
+ promise.resolve();
});
element.value = 'test';
MockInteractions.pressAndReleaseKeyOn(
@@ -74,6 +76,7 @@
null,
'enter'
);
+ await promise;
});
test('input blurred after commit', () => {
@@ -176,7 +179,7 @@
});
});
- test('Autocompletes groups', done => {
+ test('Autocompletes groups', async () => {
sinon
.stub(element, 'groupSuggestions')
.callsFake(() =>
@@ -185,13 +188,11 @@
{text: 'ownerin:gerrit'},
])
);
- element._getSearchSuggestions('ownerin:pol').then(s => {
- assert.equal(s[0].value, 'ownerin:Polygerrit');
- done();
- });
+ const s = await element._getSearchSuggestions('ownerin:pol');
+ assert.equal(s[0].value, 'ownerin:Polygerrit');
});
- test('Autocompletes projects', done => {
+ test('Autocompletes projects', async () => {
sinon
.stub(element, 'projectSuggestions')
.callsFake(() =>
@@ -201,27 +202,21 @@
{text: 'project:gerrittest'},
])
);
- element._getSearchSuggestions('project:pol').then(s => {
- assert.equal(s[0].value, 'project:Polygerrit');
- done();
- });
+ const s = await element._getSearchSuggestions('project:pol');
+ assert.equal(s[0].value, 'project:Polygerrit');
});
- test('Autocompletes simple searches', done => {
- element._getSearchSuggestions('is:o').then(s => {
- assert.equal(s[0].name, 'is:open');
- assert.equal(s[0].value, 'is:open');
- assert.equal(s[1].name, 'is:owner');
- assert.equal(s[1].value, 'is:owner');
- done();
- });
+ test('Autocompletes simple searches', async () => {
+ const s = await element._getSearchSuggestions('is:o');
+ assert.equal(s[0].name, 'is:open');
+ assert.equal(s[0].value, 'is:open');
+ assert.equal(s[1].name, 'is:owner');
+ assert.equal(s[1].value, 'is:owner');
});
- test('Does not autocomplete with no match', done => {
- element._getSearchSuggestions('asdasdasdasd').then(s => {
- assert.equal(s.length, 0);
- done();
- });
+ test('Does not autocomplete with no match', async () => {
+ const s = await element._getSearchSuggestions('asdasdasdasd');
+ assert.equal(s.length, 0);
});
test('Autocompletes without is:mergable when disabled', async () => {
@@ -235,7 +230,7 @@
'REF_UPDATED_AND_CHANGE_REINDEX',
].forEach(mergeability => {
suite(`mergeability as ${mergeability}`, () => {
- setup(done => {
+ setup(async () => {
stubRestApi('getConfig').returns(
Promise.resolve({
...createServerInfo(),
@@ -248,24 +243,22 @@
);
element = basicFixture.instantiate();
- flush(done);
+ await flush();
});
- test('Autocompltes with is:mergable when enabled', done => {
- element._getSearchSuggestions('is:mergeab').then(s => {
- assert.equal(s.length, 2);
- assert.equal(s[0].name, 'is:mergeable');
- assert.equal(s[0].value, 'is:mergeable');
- assert.equal(s[1].name, '-is:mergeable');
- assert.equal(s[1].value, '-is:mergeable');
- done();
- });
+ test('Autocompltes with is:mergable when enabled', async () => {
+ const s = await element._getSearchSuggestions('is:mergeab');
+ assert.equal(s.length, 2);
+ assert.equal(s[0].name, 'is:mergeable');
+ assert.equal(s[0].value, 'is:mergeable');
+ assert.equal(s[1].name, '-is:mergeable');
+ assert.equal(s[1].value, '-is:mergeable');
});
});
});
suite('doc url', () => {
- setup(done => {
+ setup(async () => {
stubRestApi('getConfig').returns(
Promise.resolve({
...createServerInfo(),
@@ -278,7 +271,7 @@
_testOnly_clearDocsBaseUrlCache();
element = basicFixture.instantiate();
- flush(done);
+ await flush();
});
test('compute help doc url with correct path', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index aa01c5f..f5072b9 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -38,7 +38,7 @@
import {OpenFixPreviewEvent} from '../../../types/events';
import {appContext} from '../../../services/app-context';
import {fireCloseFixPreview, fireEvent} from '../../../utils/event-util';
-import {ParsedChangeInfo} from '../../../types/types';
+import {DiffLayer, ParsedChangeInfo} from '../../../types/types';
import {GrButton} from '../../shared/gr-button/gr-button';
import {TokenHighlightLayer} from '../gr-diff-builder/token-highlight-layer';
import {KnownExperimentId} from '../../../services/flags/flags';
@@ -99,16 +99,25 @@
})
_disableApplyFixButton = false;
- layers = appContext.flagsService.isEnabled(
- KnownExperimentId.TOKEN_HIGHLIGHTING
- )
- ? [new TokenHighlightLayer()]
- : [];
+ @property({type: Array})
+ layers: DiffLayer[] = [];
private refitOverlay?: () => void;
private readonly restApiService = appContext.restApiService;
+ constructor() {
+ super();
+ this.restApiService.getPreferences().then(prefs => {
+ if (
+ !prefs?.disable_token_highlighting &&
+ appContext.flagsService.isEnabled(KnownExperimentId.TOKEN_HIGHLIGHTING)
+ ) {
+ this.layers = [new TokenHighlightLayer(this)];
+ }
+ });
+ }
+
/**
* Given robot comment CustomEvent object, fetch diffs associated
* with first robot comment suggested fix and open dialog.
@@ -141,7 +150,7 @@
});
}
- connectedCallback() {
+ override connectedCallback() {
super.connectedCallback();
this.refitOverlay = () => {
// re-center the dialog as content changed
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
index d3d7615..94d37f5 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog_test.ts
@@ -186,6 +186,7 @@
})
);
element._isApplyFixLoading = true;
+ await flush();
const button = getConfirmButton();
assert.isTrue(button.hasAttribute('disabled'));
assert.equal(button.getAttribute('title'), '');
diff --git a/polygerrit-ui/app/elements/diff/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/elements/diff/gr-context-controls/gr-context-controls.ts
index ff275ad..af9c9d4 100644
--- a/polygerrit-ui/app/elements/diff/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/elements/diff/gr-context-controls/gr-context-controls.ts
@@ -31,14 +31,8 @@
import {fire} from '../../../utils/event-util';
import {DiffInfo} from '../../../types/diff';
import {assertIsDefined} from '../../../utils/common-util';
-import {
- css,
- customElement,
- html,
- LitElement,
- property,
- TemplateResult,
-} from 'lit-element';
+import {css, html, LitElement, TemplateResult} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {
ContextButtonType,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
index 4455bd5..44b0b8b 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-element_test.js
@@ -53,7 +53,8 @@
let element;
let builder;
- const LINE_FEED_HTML = '<span class="style-scope gr-diff br"></span>';
+ const LINE_BREAK_HTML = '<span class="style-scope gr-diff br"></span>';
+ const WBR_HTML = '<wbr class="style-scope gr-diff">';
setup(() => {
element = basicFixture.instantiate();
@@ -78,59 +79,60 @@
test('newlines 1', () => {
let text = 'abcdef';
- assert.equal(builder._formatText(text, 4, 10).innerHTML, text);
+ assert.equal(builder._formatText(text, 'NONE', 4, 10).innerHTML, text);
text = 'a'.repeat(20);
- assert.equal(builder._formatText(text, 4, 10).innerHTML,
+ assert.equal(builder._formatText(text, 'NONE', 4, 10).innerHTML,
'a'.repeat(10) +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'a'.repeat(10));
});
test('newlines 2', () => {
const text = '<span class="thumbsup">👍</span>';
- assert.equal(builder._formatText(text, 4, 10).innerHTML,
+ assert.equal(builder._formatText(text, 'NONE', 4, 10).innerHTML,
'<span clas' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
's="thumbsu' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'p">👍</span' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'>');
});
test('newlines 3', () => {
const text = '01234\t56789';
- assert.equal(builder._formatText(text, 4, 10).innerHTML,
+ assert.equal(builder._formatText(text, 'NONE', 4, 10).innerHTML,
'01234' + builder._getTabWrapper(3).outerHTML + '56' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'789');
});
test('newlines 4', () => {
const text = '👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍';
- assert.equal(builder._formatText(text, 4, 20).innerHTML,
+ assert.equal(builder._formatText(text, 'NONE', 4, 20).innerHTML,
'👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍' +
- LINE_FEED_HTML +
+ LINE_BREAK_HTML +
'👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍');
});
- test('line_length ignored if line_wrapping is true', () => {
+ test('line_length applied with <wbr> if line_wrapping is true', () => {
builder._prefs = {line_wrapping: true, tab_size: 4, line_length: 50};
const text = 'a'.repeat(51);
const line = {text, highlights: []};
+ const expected = 'a'.repeat(50) + WBR_HTML + 'a';
const result = builder._createTextEl(undefined, line).firstChild.innerHTML;
- assert.equal(result, text);
+ assert.equal(result, expected);
});
- test('line_length applied if line_wrapping is false', () => {
+ test('line_length applied with line break if line_wrapping is false', () => {
builder._prefs = {line_wrapping: false, tab_size: 4, line_length: 50};
const text = 'a'.repeat(51);
const line = {text, highlights: []};
- const expected = 'a'.repeat(50) + LINE_FEED_HTML + 'a';
+ const expected = 'a'.repeat(50) + LINE_BREAK_HTML + 'a';
const result = builder._createTextEl(undefined, line).firstChild.innerHTML;
assert.equal(result, expected);
});
@@ -173,22 +175,25 @@
test('text length with tabs and unicode', () => {
function expectTextLength(text, tabSize, expected) {
// Formatting to |expected| columns should not introduce line breaks.
- const result = builder._formatText(text, tabSize, expected);
+ const result = builder._formatText(text, 'NONE', tabSize, expected);
assert.isNotOk(result.querySelector('.contentText > .br'),
` Expected the result of: \n` +
- ` _formatText(${text}', ${tabSize}, ${expected})\n` +
+ ` _formatText(${text}', 'NONE', ${tabSize}, ${expected})\n` +
` to not contain a br. But the actual result HTML was:\n` +
` '${result.innerHTML}'\nwhereupon`);
// Increasing the line limit should produce the same markup.
- assert.equal(builder._formatText(text, tabSize, Infinity).innerHTML,
+ assert.equal(
+ builder._formatText(text, 'NONE', tabSize, Infinity).innerHTML,
result.innerHTML);
- assert.equal(builder._formatText(text, tabSize, expected + 1).innerHTML,
+ assert.equal(
+ builder._formatText(text, 'NONE', tabSize, expected + 1).innerHTML,
result.innerHTML);
// Decreasing the line limit should introduce line breaks.
if (expected > 0) {
- const tooSmall = builder._formatText(text, tabSize, expected - 1);
+ const tooSmall = builder._formatText(text,
+ 'NONE', tabSize, expected - 1);
assert.isOk(tooSmall.querySelector('.contentText > .br'),
` Expected the result of: \n` +
` _formatText(${text}', ${tabSize}, ${expected - 1})\n` +
@@ -216,7 +221,7 @@
assert.ok(wrapper);
assert.equal(wrapper.innerText, '\t');
assert.equal(
- builder._formatText(html, tabSize, Infinity).innerHTML,
+ builder._formatText(html, 'NONE', tabSize, Infinity).innerHTML,
'abc' + wrapper.outerHTML + 'def');
});
@@ -746,7 +751,7 @@
let outputEl;
let keyLocations;
- setup(done => {
+ setup(async () => {
const prefs = {
line_length: 10,
show_tabs: true,
@@ -781,11 +786,11 @@
return builder;
});
element.diff = {content};
- element.render(keyLocations, prefs).then(done);
+ await element.render(keyLocations, prefs);
});
- test('addColumns is called', done => {
- element.render(keyLocations, {}).then(done);
+ test('addColumns is called', async () => {
+ await element.render(keyLocations, {});
assert.isTrue(element._builder.addColumns.called);
});
@@ -807,15 +812,13 @@
assert.strictEqual(sections[1], section[1]);
});
- test('render-start and render-content are fired', done => {
+ test('render-start and render-content are fired', async () => {
const dispatchEventStub = sinon.stub(element, 'dispatchEvent');
- element.render(keyLocations, {}).then(() => {
- const firedEventTypes = dispatchEventStub.getCalls()
- .map(c => c.args[0].type);
- assert.include(firedEventTypes, 'render-start');
- assert.include(firedEventTypes, 'render-content');
- done();
- });
+ await element.render(keyLocations, {});
+ const firedEventTypes = dispatchEventStub.getCalls()
+ .map(c => c.args[0].type);
+ assert.include(firedEventTypes, 'render-start');
+ assert.include(firedEventTypes, 'render-content');
});
test('cancel', () => {
@@ -832,7 +835,7 @@
let prefs;
let keyLocations;
- setup(done => {
+ setup(async () => {
element = mockDiffFixture.instantiate();
diff = getMockDiffResponse();
element.diff = diff;
@@ -844,10 +847,8 @@
};
keyLocations = {left: {}, right: {}};
- element.render(keyLocations, prefs).then(() => {
- builder = element._builder;
- done();
- });
+ await element.render(keyLocations, prefs);
+ builder = element._builder;
});
test('aria-labels on added line numbers', () => {
@@ -981,34 +982,30 @@
assert.isTrue(lineNumberEl.classList.contains('right'));
});
- test('_getLineNumberEl unified left', done => {
+ test('_getLineNumberEl unified left', async () => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render(keyLocations, prefs).then(() => {
- builder = element._builder;
+ await element.render(keyLocations, prefs);
+ builder = element._builder;
- const contentEl = builder.getContentByLine(5, 'left',
- element.$.diffTable);
- const lineNumberEl = builder._getLineNumberEl(contentEl, 'left');
- assert.isTrue(lineNumberEl.classList.contains('lineNum'));
- assert.isTrue(lineNumberEl.classList.contains('left'));
- done();
- });
+ const contentEl = builder.getContentByLine(5, 'left',
+ element.$.diffTable);
+ const lineNumberEl = builder._getLineNumberEl(contentEl, 'left');
+ assert.isTrue(lineNumberEl.classList.contains('lineNum'));
+ assert.isTrue(lineNumberEl.classList.contains('left'));
});
- test('_getLineNumberEl unified right', done => {
+ test('_getLineNumberEl unified right', async () => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render(keyLocations, prefs).then(() => {
- builder = element._builder;
+ await element.render(keyLocations, prefs);
+ builder = element._builder;
- const contentEl = builder.getContentByLine(5, 'right',
- element.$.diffTable);
- const lineNumberEl = builder._getLineNumberEl(contentEl, 'right');
- assert.isTrue(lineNumberEl.classList.contains('lineNum'));
- assert.isTrue(lineNumberEl.classList.contains('right'));
- done();
- });
+ const contentEl = builder.getContentByLine(5, 'right',
+ element.$.diffTable);
+ const lineNumberEl = builder._getLineNumberEl(contentEl, 'right');
+ assert.isTrue(lineNumberEl.classList.contains('lineNum'));
+ assert.isTrue(lineNumberEl.classList.contains('right'));
});
test('_getNextContentOnSide side-by-side left', () => {
@@ -1035,44 +1032,38 @@
assert.equal(nextElem.textContent, expectedNextString);
});
- test('_getNextContentOnSide unified left', done => {
+ test('_getNextContentOnSide unified left', async () => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render(keyLocations, prefs).then(() => {
- builder = element._builder;
+ await element.render(keyLocations, prefs);
+ builder = element._builder;
- const startElem = builder.getContentByLine(5, 'left',
- element.$.diffTable);
- const expectedStartString = diff.content[2].ab[0];
- const expectedNextString = diff.content[2].ab[1];
- assert.equal(startElem.textContent, expectedStartString);
+ const startElem = builder.getContentByLine(5, 'left',
+ element.$.diffTable);
+ const expectedStartString = diff.content[2].ab[0];
+ const expectedNextString = diff.content[2].ab[1];
+ assert.equal(startElem.textContent, expectedStartString);
- const nextElem = builder._getNextContentOnSide(startElem,
- 'left');
- assert.equal(nextElem.textContent, expectedNextString);
-
- done();
- });
+ const nextElem = builder._getNextContentOnSide(startElem,
+ 'left');
+ assert.equal(nextElem.textContent, expectedNextString);
});
- test('_getNextContentOnSide unified right', done => {
+ test('_getNextContentOnSide unified right', async () => {
// Re-render as unified:
element.viewMode = 'UNIFIED_DIFF';
- element.render(keyLocations, prefs).then(() => {
- builder = element._builder;
+ await element.render(keyLocations, prefs);
+ builder = element._builder;
- const startElem = builder.getContentByLine(5, 'right',
- element.$.diffTable);
- const expectedStartString = diff.content[1].b[0];
- const expectedNextString = diff.content[1].b[1];
- assert.equal(startElem.textContent, expectedStartString);
+ const startElem = builder.getContentByLine(5, 'right',
+ element.$.diffTable);
+ const expectedStartString = diff.content[1].b[0];
+ const expectedNextString = diff.content[1].b[1];
+ assert.equal(startElem.textContent, expectedStartString);
- const nextElem = builder._getNextContentOnSide(startElem,
- 'right');
- assert.equal(nextElem.textContent, expectedNextString);
-
- done();
- });
+ const nextElem = builder._getNextContentOnSide(startElem,
+ 'right');
+ assert.equal(nextElem.textContent, expectedNextString);
});
test('escaping HTML', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
index 057b926..bd7dc29 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.ts
@@ -39,6 +39,7 @@
numberOfCells: 4,
movedOutIndex: 1,
movedInIndex: 3,
+ lineNumberCols: [0, 2],
};
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
index b2dfa61..a7b3a42 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.ts
@@ -38,6 +38,7 @@
numberOfCells: 3,
movedOutIndex: 2,
movedInIndex: 2,
+ lineNumberCols: [0, 1],
};
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
index 987f808..663ee7e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.ts
@@ -89,6 +89,12 @@
return 'NONE';
}
+export function isResponsive(responsiveMode: DiffResponsiveMode) {
+ return (
+ responsiveMode === 'FULL_RESPONSIVE' || responsiveMode === 'SHRINK_ONLY'
+ );
+}
+
export abstract class GrDiffBuilder {
private readonly _diff: DiffInfo;
@@ -513,12 +519,11 @@
const {beforeNumber, afterNumber} = line;
if (beforeNumber !== 'FILE' && beforeNumber !== 'LOST') {
const responsiveMode = getResponsiveMode(this._prefs, this._renderPrefs);
- const lineLimit =
- responsiveMode === 'NONE' ? this._prefs.line_length : Infinity;
const contentText = this._formatText(
line.text,
+ responsiveMode,
this._prefs.tab_size,
- lineLimit
+ this._prefs.line_length
);
if (side) {
@@ -544,6 +549,12 @@
return td;
}
+ private createLineBreak(responsive: boolean) {
+ return responsive
+ ? this._createElement('wbr')
+ : this._createElement('span', 'br');
+ }
+
/**
* Returns a 'div' element containing the supplied |text| as its innerText,
* with '\t' characters expanded to a width determined by |tabSize|, and the
@@ -554,9 +565,15 @@
* @param tabSize The width of each tab stop.
* @param lineLimit The column after which to wrap lines.
*/
- _formatText(text: string, tabSize: number, lineLimit: number): HTMLElement {
+ _formatText(
+ text: string,
+ responsiveMode: DiffResponsiveMode,
+ tabSize: number,
+ lineLimit: number
+ ): HTMLElement {
const contentText = this._createElement('div', 'contentText');
-
+ contentText.ariaLabel = text;
+ const responsive = isResponsive(responsiveMode);
let columnPos = 0;
let textOffset = 0;
for (const segment of text.split(REGEX_TAB_OR_SURROGATE_PAIR)) {
@@ -570,7 +587,7 @@
contentText.appendChild(
document.createTextNode(segment.substring(rowStart, rowEnd))
);
- contentText.appendChild(this._createElement('span', 'br'));
+ contentText.appendChild(this.createLineBreak(responsive));
columnPos = 0;
rowStart = rowEnd;
rowEnd += lineLimit;
@@ -588,7 +605,7 @@
// Append a single '\t' character.
let effectiveTabSize = tabSize - (columnPos % tabSize);
if (columnPos + effectiveTabSize > lineLimit) {
- contentText.appendChild(this._createElement('span', 'br'));
+ contentText.appendChild(this.createLineBreak(responsive));
columnPos = 0;
effectiveTabSize = tabSize;
}
@@ -598,7 +615,7 @@
} else {
// Append a single surrogate pair.
if (columnPos >= lineLimit) {
- contentText.appendChild(this._createElement('span', 'br'));
+ contentText.appendChild(this.createLineBreak(responsive));
columnPos = 0;
}
contentText.appendChild(
@@ -667,6 +684,7 @@
numberOfCells: number;
movedOutIndex: number;
movedInIndex: number;
+ lineNumberCols: number[];
};
/**
@@ -760,7 +778,7 @@
_buildMoveControls(group: GrDiffGroup) {
const movedIn = group.adds.length > 0;
- const {numberOfCells, movedOutIndex, movedInIndex} =
+ const {numberOfCells, movedOutIndex, movedInIndex, lineNumberCols} =
this._getMoveControlsConfig();
let controlsClass;
@@ -778,6 +796,9 @@
const cells = [...Array(numberOfCells).keys()].map(() =>
this._createElement('td')
);
+ lineNumberCols.forEach(index => {
+ cells[index].classList.add('moveControlsLineNumCol');
+ });
const moveRangeHeader = this._createElement('gr-range-header');
moveRangeHeader.setAttribute('icon', 'gr-icons:move-item');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
index 647f701..de7d007 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer.ts
@@ -15,9 +15,17 @@
* limitations under the License.
*/
import {DiffLayer, DiffLayerListener} from '../../../types/types';
-import {GrDiffLine, Side} from '../../../api/diff';
+import {GrDiffLine, Side, TokenHighlightListener} from '../../../api/diff';
+import {assertIsDefined} from '../../../utils/common-util';
import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
import {debounce, DelayedTask} from '../../../utils/async-util';
+
+import {
+ getLineElByChild,
+ getSideByLineEl,
+ getPreviousContentNodes,
+} from '../gr-diff/gr-diff-utils';
+
import {
getLineNumberByChild,
lineNumberToNumber,
@@ -31,7 +39,7 @@
/** CSS class for the currently hovered token. */
const CSS_HIGHLIGHT = 'token-highlight';
-const HOVER_DELAY_MS = 200;
+export const HOVER_DELAY_MS = 200;
const LINE_LENGTH_LIMIT = 500;
@@ -42,11 +50,10 @@
const TOKEN_OCCURRENCES_LIMIT = 1000;
/**
- * Token highlighting is only useful for code on-screen, so don't bother
- * highlighting tokens that are further away than this threshold from where the
- * user is hovering.
+ * Token highlighting is only useful for code on-screen, so we only highlight
+ * the nearest set of tokens up to this limit.
*/
-const LINE_DISTANCE_THRESHOLD = 100;
+const TOKEN_HIGHLIGHT_LIMIT = 100;
/**
* When a user hovers over a token in the diff, then this layer makes sure that
@@ -66,6 +73,9 @@
/** The currently highlighted token. */
private currentHighlight?: string;
+ /** Trigger when a new token starts or stoped being highlighted.*/
+ private readonly tokenHighlightListener?: TokenHighlightListener;
+
/**
* The line of the currently highlighted token. We store this in order to
* re-render only relevant lines of the diff. Only lines visible on the screen
@@ -96,9 +106,13 @@
private updateTokenTask?: DelayedTask;
- constructor() {
- window.addEventListener('click', _ => {
- this.handleWindowClick();
+ constructor(
+ container: HTMLElement = document.documentElement,
+ tokenHighlightListener?: TokenHighlightListener
+ ) {
+ this.tokenHighlightListener = tokenHighlightListener;
+ container.addEventListener('click', e => {
+ this.handleContainerClick(e);
});
}
@@ -137,10 +151,10 @@
// garbage collected along with the element itself once it is not attached
// to the DOM anymore and no references exist anymore.
el.addEventListener('mouseover', e => {
- this.handleMouseOver(e);
+ this.handleTokenMouseOver(e);
});
el.addEventListener('mouseout', e => {
- this.handleMouseOut(e);
+ this.handleTokenMouseOut(e);
});
}
}
@@ -162,10 +176,10 @@
numbers.add(Number(lineNumber));
}
- private handleMouseOut(e: MouseEvent) {
+ private handleTokenMouseOut(e: MouseEvent) {
// If there's no ongoing hover-task, terminate early.
if (!this.updateTokenTask?.isActive()) return;
- if (this.interferesWithSelection(e)) return;
+ if (e.buttons > 0 || this.interferesWithSelection()) return;
const {element} = this.findTokenAncestor(e?.target);
if (!element) return;
if (element === this.hoveredElement) {
@@ -176,8 +190,8 @@
}
}
- private handleMouseOver(e: MouseEvent) {
- if (this.interferesWithSelection(e)) return;
+ private handleTokenMouseOver(e: MouseEvent) {
+ if (e.buttons > 0 || this.interferesWithSelection()) return;
const {
line,
token: newHighlight,
@@ -189,36 +203,26 @@
this.updateTokenTask = debounce(
this.updateTokenTask,
() => {
- this.updateTokenHighlight(newHighlight, line);
+ this.updateTokenHighlight(newHighlight, line, element);
},
HOVER_DELAY_MS
);
}
- private interferesWithSelection(e: MouseEvent) {
- if (e.buttons > 0) return true;
- if (window.getSelection()?.type === 'Range') return true;
- return false;
- }
-
- private handleWindowClick() {
+ private handleContainerClick(e: MouseEvent) {
+ if (this.interferesWithSelection()) return;
+ // Ignore the click if the click is on a token.
+ // We can't use e.target becauses it gets retargetted to the container as
+ // it's a shadow dom.
+ const {element} = this.findTokenAncestor(e.composedPath()[0]);
+ if (element) return;
this.hoveredElement = undefined;
this.updateTokenTask?.cancel();
- this.updateTokenHighlight(undefined, 0);
+ this.updateTokenHighlight(undefined, 0, undefined);
}
- private updateTokenHighlight(
- newHighlight: string | undefined,
- newLineNumber: number
- ) {
- const oldHighlight = this.currentHighlight;
- const oldLineNumber = this.currentHighlightLineNumber;
- this.currentHighlight = newHighlight;
- this.currentHighlightLineNumber = newLineNumber;
- this.notifyForToken(oldHighlight, oldLineNumber);
- this.notifyForToken(newHighlight, newLineNumber);
- // Reset the hovered element.
- this.hoveredElement = undefined;
+ private interferesWithSelection() {
+ return document.getSelection()?.type === 'Range';
}
findTokenAncestor(el?: EventTarget | Element | null): {
@@ -250,20 +254,94 @@
return (linesLeft?.size ?? 0) + (linesRight?.size ?? 0);
}
+ private updateTokenHighlight(
+ newHighlight: string | undefined,
+ newLineNumber: number,
+ newHoveredElement: Element | undefined
+ ) {
+ if (
+ this.currentHighlight === newHighlight &&
+ this.currentHighlightLineNumber === newLineNumber
+ )
+ return;
+ const oldHighlight = this.currentHighlight;
+ const oldLineNumber = this.currentHighlightLineNumber;
+ this.currentHighlight = newHighlight;
+ this.currentHighlightLineNumber = newLineNumber;
+ this.triggerTokenHighlightEvent(
+ newHighlight,
+ newLineNumber,
+ newHoveredElement
+ );
+ this.notifyForToken(oldHighlight, oldLineNumber);
+ this.notifyForToken(newHighlight, newLineNumber);
+ }
+
+ triggerTokenHighlightEvent(
+ token: string | undefined,
+ line: number,
+ element: Element | undefined
+ ) {
+ if (!this.tokenHighlightListener) {
+ return;
+ }
+ if (!token || !element) {
+ this.tokenHighlightListener(undefined);
+ return;
+ }
+ const previousTextLength = getPreviousContentNodes(element)
+ .map(sib => sib.textContent!.length)
+ .reduce((partial_sum, a) => partial_sum + a, 0);
+ const lineEl = getLineElByChild(element);
+ assertIsDefined(lineEl, 'Line element should be found!');
+ const side = getSideByLineEl(lineEl);
+ const range = {
+ start_line: line,
+ start_column: previousTextLength + 1, // 1-based inclusive
+ end_line: line,
+ end_column: previousTextLength + token.length, // 1-based inclusive
+ };
+ this.tokenHighlightListener({token, element, side, range});
+ }
+
+ getSortedLinesForSide(
+ lineMapping: Map<string, Set<number>>,
+ token: string | undefined,
+ lineNumber: number
+ ): Array<number> {
+ if (!token) return [];
+ const lineSet = lineMapping.get(token);
+ if (!lineSet) return [];
+ const lines = [...lineSet];
+ lines.sort((a, b) => {
+ const da = Math.abs(a - lineNumber);
+ const db = Math.abs(b - lineNumber);
+ // For equal distance, prefer lines later in the file over earlier in the
+ // file. This ensures total ordering.
+ if (da === db) return b - a;
+ // Compare the distance to lineNumber.
+ return da - db;
+ });
+ return lines.slice(0, TOKEN_HIGHLIGHT_LIMIT);
+ }
+
notifyForToken(token: string | undefined, lineNumber: number) {
- if (!token) return;
- const linesLeft = this.tokenToLinesLeft.get(token);
- linesLeft?.forEach(line => {
- if (Math.abs(line - lineNumber) < LINE_DISTANCE_THRESHOLD) {
- this.notifyListeners(line, Side.LEFT);
- }
- });
- const linesRight = this.tokenToLinesRight.get(token);
- linesRight?.forEach(line => {
- if (Math.abs(line - lineNumber) < LINE_DISTANCE_THRESHOLD) {
- this.notifyListeners(line, Side.RIGHT);
- }
- });
+ const leftLines = this.getSortedLinesForSide(
+ this.tokenToLinesLeft,
+ token,
+ lineNumber
+ );
+ for (const line of leftLines) {
+ this.notifyListeners(line, Side.LEFT);
+ }
+ const rightLines = this.getSortedLinesForSide(
+ this.tokenToLinesRight,
+ token,
+ lineNumber
+ );
+ for (const line of rightLines) {
+ this.notifyListeners(line, Side.RIGHT);
+ }
}
addListener(listener: DiffLayerListener) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts
new file mode 100644
index 0000000..2993d35
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/token-highlight-layer_test.ts
@@ -0,0 +1,339 @@
+/**
+ * @license
+ * 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.
+ */
+
+import '../../../test/common-test-setup-karma';
+import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
+import {Side, TokenHighlightEventDetails} from '../../../api/diff';
+import {GrDiffLine, GrDiffLineType} from '../gr-diff/gr-diff-line.js';
+import {HOVER_DELAY_MS, TokenHighlightLayer} from './token-highlight-layer';
+import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {html, render} from 'lit';
+import {_testOnly_allTasks} from '../../../utils/async-util';
+import {queryAndAssert} from '../../../test/test-utils';
+
+// MockInteractions.makeMouseEvent always sets buttons to 1.
+function dispatchMouseEvent(
+ type: string,
+ xy: {x: number; y: number},
+ node: Element
+) {
+ const props = {
+ bubbles: true,
+ cancellable: true,
+ composed: true,
+ clientX: xy.x,
+ clientY: xy.y,
+ buttons: 0,
+ };
+ node.dispatchEvent(new MouseEvent(type, props));
+}
+
+class MockListener {
+ private results: any[][] = [];
+
+ notify(...args: any[]) {
+ this.results.push(args);
+ }
+
+ shift() {
+ return this.results.shift();
+ }
+
+ flush() {
+ this.results = [];
+ }
+
+ get pending(): number {
+ return this.results.length;
+ }
+}
+
+suite('token-highlight-layer', () => {
+ let container: HTMLElement;
+ let listener: MockListener;
+ let highlighter: TokenHighlightLayer;
+ let tokenHighlightingCalls: {details?: TokenHighlightEventDetails}[] = [];
+
+ function tokenHighlightListener(
+ highlightDetails?: TokenHighlightEventDetails
+ ) {
+ tokenHighlightingCalls.push({details: highlightDetails});
+ }
+
+ setup(async () => {
+ listener = new MockListener();
+ tokenHighlightingCalls = [];
+ container = document.createElement('div');
+ document.body.appendChild(container);
+ highlighter = new TokenHighlightLayer(container, tokenHighlightListener);
+ highlighter.addListener((...args) => listener.notify(...args));
+ });
+
+ teardown(() => {
+ document.body.removeChild(container);
+ });
+
+ function annotate(el: HTMLElement, side: Side = Side.LEFT, line = 1) {
+ const diffLine = new GrDiffLine(GrDiffLineType.BOTH);
+ diffLine.afterNumber = line;
+ diffLine.beforeNumber = line;
+ highlighter.annotate(el, document.createElement('div'), diffLine, side);
+ return el;
+ }
+
+ let uniqueId = 0;
+ function createLineId() {
+ uniqueId++;
+ return `line-${uniqueId.toString()}`;
+ }
+
+ function createLine(text: string, line = 1): HTMLElement {
+ const lineId = createLineId();
+ const template = html`
+ <div class="line">
+ <div data-value=${line} class="lineNum right"></div>
+ <div class="content">
+ <div id=${lineId} class="contentText">${text}</div>
+ </div>
+ </div>
+ `;
+
+ const div = document.createElement('div');
+ render(template, div);
+ container.appendChild(div);
+ const el = queryAndAssert(container, `#${lineId}`);
+ return el as HTMLElement;
+ }
+
+ suite('annotate', () => {
+ function assertAnnotation(
+ args: any[],
+ el: HTMLElement,
+ start: number,
+ length: number,
+ cssClass: string
+ ) {
+ assert.equal(args[0], el);
+ assert.equal(args[1], start);
+ assert.equal(args[2], length);
+ assert.equal(args[3], cssClass);
+ }
+
+ test('annotate adds css token', () => {
+ const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+ const el = createLine('these are words');
+ annotate(el);
+ assert.isTrue(annotateElementStub.calledThrice);
+ assertAnnotation(annotateElementStub.args[0], el, 0, 5, 'tk-these token');
+ assertAnnotation(annotateElementStub.args[1], el, 6, 3, 'tk-are token');
+ assertAnnotation(
+ annotateElementStub.args[2],
+ el,
+ 10,
+ 5,
+ 'tk-words token'
+ );
+ });
+
+ test('annotate adds mouse handlers', () => {
+ const el = createLine('these are words');
+ const addEventListenerStub = sinon.stub(el, 'addEventListener');
+ annotate(el);
+ assert.isTrue(addEventListenerStub.calledTwice);
+ assert.equal(addEventListenerStub.args[0][0], 'mouseover');
+ assert.equal(addEventListenerStub.args[1][0], 'mouseout');
+ });
+
+ test('annotate does not add mouse handlers without words', () => {
+ const el = createLine(' ');
+ const addEventListenerStub = sinon.stub(el, 'addEventListener');
+ annotate(el);
+ assert.isFalse(addEventListenerStub.called);
+ });
+
+ test('annotate adds mouse handlers for longest word', () => {
+ const el = createLine('w'.repeat(100));
+ const addEventListenerStub = sinon.stub(el, 'addEventListener');
+ annotate(el);
+ assert.isTrue(addEventListenerStub.called);
+ });
+
+ test('annotate does not add mouse handlers for long words', () => {
+ const el = createLine('w'.repeat(101));
+ const addEventListenerStub = sinon.stub(el, 'addEventListener');
+ annotate(el);
+ assert.isFalse(addEventListenerStub.called);
+ });
+ });
+
+ suite('highlight', () => {
+ test('highlighting hover delay', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words');
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+
+ assert.equal(listener.pending, 0);
+ assert.equal(_testOnly_allTasks.size, 1);
+
+ // Too early for hover behavior to trigger.
+ clock.tick(100);
+ assert.equal(listener.pending, 0);
+ assert.equal(_testOnly_allTasks.size, 1);
+
+ // After a total of HOVER_DELAY_MS ms the hover behavior should trigger.
+ clock.tick(HOVER_DELAY_MS - 100);
+ assert.equal(listener.pending, 2);
+ assert.equal(_testOnly_allTasks.size, 0);
+ assert.deepEqual(listener.shift(), [1, 1, Side.LEFT]);
+ assert.deepEqual(listener.shift(), [2, 2, Side.RIGHT]);
+ });
+
+ test('highlighting spans many lines', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words');
+ annotate(line2, Side.RIGHT, 1000);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+
+ assert.equal(listener.pending, 0);
+
+ // After a total of HOVER_DELAY_MS ms the hover behavior should trigger.
+ clock.tick(HOVER_DELAY_MS);
+ assert.equal(listener.pending, 2);
+ assert.equal(_testOnly_allTasks.size, 0);
+ assert.deepEqual(listener.shift(), [1, 1, Side.LEFT]);
+ assert.deepEqual(listener.shift(), [1000, 1000, Side.RIGHT]);
+ });
+
+ test('highlighting mouse out before delay', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words', 2);
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(listener.pending, 0);
+ clock.tick(100);
+ // Mouse out after 100ms but before hover delay.
+ dispatchMouseEvent(
+ 'mouseout',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(listener.pending, 0);
+ clock.tick(HOVER_DELAY_MS - 100);
+ assert.equal(listener.pending, 0);
+ assert.equal(_testOnly_allTasks.size, 0);
+ });
+
+ test('triggers listener for applying and clearing highlighting', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words', 2);
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(tokenHighlightingCalls.length, 0);
+ clock.tick(HOVER_DELAY_MS);
+ assert.equal(tokenHighlightingCalls.length, 1);
+ assert.deepEqual(tokenHighlightingCalls[0].details, {
+ token: 'words',
+ side: Side.RIGHT,
+ element: words1,
+ range: {start_line: 1, start_column: 5, end_line: 1, end_column: 9},
+ });
+
+ MockInteractions.click(container);
+ assert.equal(tokenHighlightingCalls.length, 2);
+ assert.deepEqual(tokenHighlightingCalls[1].details, undefined);
+ });
+
+ test('clicking clears highlight', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words', 2);
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(listener.pending, 0);
+ clock.tick(HOVER_DELAY_MS);
+ assert.equal(listener.pending, 2);
+ listener.flush();
+ assert.equal(listener.pending, 0);
+ MockInteractions.click(container);
+ assert.equal(listener.pending, 2);
+ assert.deepEqual(listener.shift(), [1, 1, Side.LEFT]);
+ assert.deepEqual(listener.shift(), [2, 2, Side.RIGHT]);
+ });
+
+ test('clicking on word does not clear highlight', async () => {
+ const clock = sinon.useFakeTimers();
+ const line1 = createLine('two words');
+ annotate(line1);
+ const line2 = createLine('three words', 2);
+ annotate(line2, Side.RIGHT, 2);
+ const words1 = queryAndAssert(line1, '.tk-words');
+ assert.isTrue(words1.classList.contains('token'));
+ dispatchMouseEvent(
+ 'mouseover',
+ MockInteractions.middleOfNode(words1),
+ words1
+ );
+ assert.equal(listener.pending, 0);
+ clock.tick(HOVER_DELAY_MS);
+ assert.equal(listener.pending, 2);
+ listener.flush();
+ assert.equal(listener.pending, 0);
+ MockInteractions.click(words1);
+ assert.equal(listener.pending, 0);
+ });
+ });
+});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
index 3e63b0a..3b604eb 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
@@ -19,7 +19,7 @@
import '../gr-diff/gr-diff.js';
import './gr-diff-cursor.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-import {listenOnce} from '../../../test/test-utils.js';
+import {listenOnce, mockPromise} from '../../../test/test-utils.js';
import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
import {createDefaultDiffPrefs} from '../../../constants/constants.js';
import {GrDiffCursor} from './gr-diff-cursor.js';
@@ -33,7 +33,7 @@
let diffElement;
let diff;
- setup(done => {
+ setup(async () => {
diffElement = basicFixture.instantiate();
cursor = new GrDiffCursor();
@@ -48,17 +48,19 @@
meta: {patchRange: undefined},
};
diffElement.path = 'some/path.ts';
+ const promise = mockPromise();
const setupDone = () => {
cursor._updateStops();
cursor.moveToFirstChunk();
diffElement.removeEventListener('render', setupDone);
- done();
+ promise.resolve();
};
diffElement.addEventListener('render', setupDone);
diff = getMockDiffResponse();
diffElement.prefs = createDefaultDiffPrefs();
diffElement.diff = diff;
+ await promise;
});
test('diff cursor functionality (side-by-side)', () => {
@@ -215,15 +217,17 @@
});
suite('unified diff', () => {
- setup(done => {
+ setup(async () => {
+ const promise = mockPromise();
// We must allow the diff to re-render after setting the viewMode.
const renderHandler = function() {
diffElement.removeEventListener('render', renderHandler);
cursor.reInitCursor();
- done();
+ promise.resolve();
};
diffElement.addEventListener('render', renderHandler);
diffElement.viewMode = 'UNIFIED_DIFF';
+ await promise;
});
test('diff cursor functionality (unified)', () => {
@@ -312,11 +316,12 @@
});
suite('moved chunks without line range)', () => {
- setup(done => {
+ setup(async () => {
+ const promise = mockPromise();
const renderHandler = function() {
diffElement.removeEventListener('render', renderHandler);
cursor.reInitCursor();
- done();
+ promise.resolve();
};
diffElement.addEventListener('render', renderHandler);
diffElement.diff = {...diff, content: [
@@ -352,6 +357,7 @@
],
},
]};
+ await promise;
});
test('renders moveControls with simple descriptions', () => {
@@ -363,11 +369,12 @@
});
suite('moved chunks (moveDetails)', () => {
- setup(done => {
+ setup(async () => {
+ const promise = mockPromise();
const renderHandler = function() {
diffElement.removeEventListener('render', renderHandler);
cursor.reInitCursor();
- done();
+ promise.resolve();
};
diffElement.addEventListener('render', renderHandler);
diffElement.diff = {...diff, content: [
@@ -403,6 +410,7 @@
],
},
]};
+ await promise;
});
test('renders moveControls with simple descriptions', () => {
@@ -412,37 +420,41 @@
assert.equal(movedOut.textContent, 'Moved to lines 2 - 4');
});
- test('startLineAnchor of movedIn chunk fires events', done => {
+ test('startLineAnchor of movedIn chunk fires events', async () => {
const [movedIn] = diffElement.root
.querySelectorAll('.dueToMove .moveControls');
const [startLineAnchor] = movedIn.querySelectorAll('a');
+ const promise = mockPromise();
const onMovedLinkClicked = e => {
assert.deepEqual(e.detail, {lineNum: 4, side: 'left'});
- done();
+ promise.resolve();
};
assert.equal(startLineAnchor.textContent, '4');
startLineAnchor
.addEventListener('moved-link-clicked', onMovedLinkClicked);
MockInteractions.click(startLineAnchor);
+ await promise;
});
- test('endLineAnchor of movedOut fires events', done => {
+ test('endLineAnchor of movedOut fires events', async () => {
const [, movedOut] = diffElement.root
.querySelectorAll('.dueToMove .moveControls');
const [, endLineAnchor] = movedOut.querySelectorAll('a');
+ const promise = mockPromise();
const onMovedLinkClicked = e => {
assert.deepEqual(e.detail, {lineNum: 4, side: 'right'});
- done();
+ promise.resolve();
};
assert.equal(endLineAnchor.textContent, '4');
endLineAnchor.addEventListener('moved-link-clicked', onMovedLinkClicked);
MockInteractions.click(endLineAnchor);
+ await promise;
});
});
- test('initialLineNumber not provided', done => {
+ test('initialLineNumber not provided', async () => {
let scrollBehaviorDuringMove;
const moveToNumStub = sinon.stub(cursor, 'moveToLineNumber');
const moveToChunkStub = sinon.stub(cursor, 'moveToFirstChunk')
@@ -450,6 +462,7 @@
scrollBehaviorDuringMove = cursor.cursorManager.scrollMode;
});
+ const promise = mockPromise();
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
cursor.reInitCursor();
@@ -457,19 +470,21 @@
assert.isTrue(moveToChunkStub.called);
assert.equal(scrollBehaviorDuringMove, 'never');
assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
- done();
+ promise.resolve();
}
diffElement.addEventListener('render', renderHandler);
diffElement._diffChanged(getMockDiffResponse());
+ await promise;
});
- test('initialLineNumber provided', done => {
+ test('initialLineNumber provided', async () => {
let scrollBehaviorDuringMove;
const moveToNumStub = sinon.stub(cursor, 'moveToLineNumber')
.callsFake(() => {
scrollBehaviorDuringMove = cursor.cursorManager.scrollMode;
});
const moveToChunkStub = sinon.stub(cursor, 'moveToFirstChunk');
+ const promise = mockPromise();
function renderHandler() {
diffElement.removeEventListener('render', renderHandler);
cursor.reInitCursor();
@@ -479,13 +494,14 @@
assert.equal(moveToNumStub.lastCall.args[1], 'right');
assert.equal(scrollBehaviorDuringMove, 'keep-visible');
assert.equal(cursor.cursorManager.scrollMode, 'keep-visible');
- done();
+ promise.resolve();
}
diffElement.addEventListener('render', renderHandler);
cursor.initialLineNumber = 10;
cursor.side = 'right';
diffElement._diffChanged(getMockDiffResponse());
+ await promise;
});
test('getTargetDiffElement', () => {
@@ -502,31 +518,35 @@
diffElement.loggedIn = true;
});
- test('adds new draft for selected line on the left', done => {
+ test('adds new draft for selected line on the left', async () => {
cursor.moveToLineNumber(2, 'left');
+ const promise = mockPromise();
diffElement.addEventListener('create-comment', e => {
const {lineNum, range, side} = e.detail;
assert.equal(lineNum, 2);
assert.equal(range, undefined);
assert.equal(side, 'left');
- done();
+ promise.resolve();
});
cursor.createCommentInPlace();
+ await promise;
});
- test('adds draft for selected line on the right', done => {
+ test('adds draft for selected line on the right', async () => {
cursor.moveToLineNumber(4, 'right');
+ const promise = mockPromise();
diffElement.addEventListener('create-comment', e => {
const {lineNum, range, side} = e.detail;
assert.equal(lineNum, 4);
assert.equal(range, undefined);
assert.equal(side, 'right');
- done();
+ promise.resolve();
});
cursor.createCommentInPlace();
+ await promise;
});
- test('creates comment for range if selected', done => {
+ test('creates comment for range if selected', async () => {
const someRange = {
start_line: 2,
start_character: 3,
@@ -537,14 +557,16 @@
side: 'right',
range: someRange,
};
+ const promise = mockPromise();
diffElement.addEventListener('create-comment', e => {
const {lineNum, range, side} = e.detail;
assert.equal(lineNum, 6);
assert.equal(range, someRange);
assert.equal(side, 'right');
- done();
+ promise.resolve();
});
cursor.createCommentInPlace();
+ await promise;
});
test('ignores call if nothing is selected', () => {
@@ -596,15 +618,13 @@
assert.equal(cursor._findRowByNumberAndFile(5, 'left'), row);
});
- test('expand context updates stops', done => {
+ test('expand context updates stops', async () => {
sinon.spy(cursor, '_updateStops');
MockInteractions.tap(diffElement.shadowRoot
.querySelector('gr-context-controls').shadowRoot
.querySelector('.showContext'));
- flush(() => {
- assert.isTrue(cursor._updateStops.called);
- done();
- });
+ await flush();
+ assert.isTrue(cursor._updateStops.called);
});
test('updates stops when loading changes', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.ts b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.ts
index 7420dc8..5e81871 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation.ts
@@ -29,6 +29,7 @@
*
*/
getLength(node: Node) {
+ if (node instanceof Comment) return 0;
return this.getStringLength(node.textContent || '');
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.js
index 65f5e07..d8295a5 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-annotation_test.js
@@ -252,6 +252,24 @@
'0<test-wrapper>123456789<span></span>0</test-wrapper>123456789');
});
+ test('handles comment nodes', () => {
+ const container = document.createElement('div');
+ container.appendChild(document.createComment('comment1'));
+ container.appendChild(document.createTextNode('0123456789'));
+ container.appendChild(document.createComment('comment2'));
+ container.appendChild(document.createElement('span'));
+ container.appendChild(document.createTextNode('0123456789'));
+ GrAnnotation.annotateWithElement(
+ container, 1, 10, {tagName: 'test-wrapper'});
+
+ assert.equal(
+ container.innerHTML,
+ '<!--comment1-->' +
+ '0<test-wrapper>123456789' +
+ '<!--comment2-->' +
+ '<span></span>0</test-wrapper>123456789');
+ });
+
test('sets sanitized attributes', () => {
const container = document.createElement('div');
container.textContent = fullText;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
index 18fbe9a..4c1295f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-highlight/gr-diff-highlight_test.js
@@ -251,7 +251,7 @@
};
const emulateSelection = (startNode, startOffset, endNode, endOffset) => {
- const selection = window.getSelection();
+ const selection = document.getSelection();
const range = document.createRange();
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
@@ -281,7 +281,7 @@
teardown(() => {
contentStubs = null;
- window.getSelection().removeAllRanges();
+ document.getSelection().removeAllRanges();
});
test('single first line', () => {
@@ -389,7 +389,7 @@
test('collapsed', () => {
const content = stubContent(138, 'left');
emulateSelection(content.firstChild, 5, content.firstChild, 5);
- assert.isOk(window.getSelection().getRangeAt(0).startContainer);
+ assert.isOk(document.getSelection().getRangeAt(0).startContainer);
assert.isFalse(!!element.selectedRange);
});
@@ -556,7 +556,7 @@
content.querySelectorAll('hl')[3], 0,
content.querySelectorAll('span')[1], 0);
const spyCall = spy.getCall(0);
- const range = window.getSelection().getRangeAt(0);
+ const range = document.getSelection().getRangeAt(0);
assert.notDeepEqual(spyCall.returnValue, range);
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index 06d31b3..90d6218 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -50,7 +50,6 @@
Base64ImageFile,
BlameInfo,
ChangeInfo,
- CommentRange,
EditPatchSetNum,
NumericChangeId,
ParentPatchSetNum,
@@ -93,7 +92,7 @@
import {Subject} from 'rxjs';
import {RenderPreferences} from '../../../api/diff';
-const MSG_EMPTY_BLAME = 'No blame information for this diff.';
+const EMPTY_BLAME = 'No blame information for this diff.';
const EVENT_AGAINST_PARENT = 'diff-against-parent';
const EVENT_ZERO_REBASE = 'rebase-percent-zero';
@@ -328,18 +327,21 @@
super.disconnectedCallback();
}
- initLayers() {
- return getPluginLoader()
- .awaitPluginsLoaded()
- .then(() => {
- assertIsDefined(this.path, 'path');
- this._layers = this._getLayers(this.path);
- this._coverageRanges = [];
- // We kick off fetching the data here, but we don't return the promise,
- // so awaiting initLayers() will not wait for coverage data to be
- // completely loaded.
- this._getCoverageData();
- });
+ async initLayers() {
+ const preferencesPromise = appContext.restApiService.getPreferences();
+ await getPluginLoader().awaitPluginsLoaded();
+ const prefs = await preferencesPromise;
+ const enableTokenHighlight =
+ appContext.flagsService.isEnabled(KnownExperimentId.TOKEN_HIGHLIGHTING) &&
+ !prefs?.disable_token_highlighting;
+
+ assertIsDefined(this.path, 'path');
+ this._layers = this.getLayers(this.path, enableTokenHighlight);
+ this._coverageRanges = [];
+ // We kick off fetching the data here, but we don't return the promise,
+ // so awaiting initLayers() will not wait for coverage data to be
+ // completely loaded.
+ this._getCoverageData();
}
diffChanged(diff?: DiffInfo) {
@@ -411,12 +413,10 @@
}
}
- private _getLayers(path: string): DiffLayer[] {
+ private getLayers(path: string, enableTokenHighlight: boolean): DiffLayer[] {
const layers = [];
- if (
- appContext.flagsService.isEnabled(KnownExperimentId.TOKEN_HIGHLIGHTING)
- ) {
- layers.push(new TokenHighlightLayer());
+ if (enableTokenHighlight) {
+ layers.push(new TokenHighlightLayer(this));
}
layers.push(this.syntaxLayer);
// Get layers from plugins (if any).
@@ -569,8 +569,8 @@
.getBlame(this.changeNum, this.patchRange.patchNum, this.path, true)
.then(blame => {
if (!blame || !blame.length) {
- fireAlert(this, MSG_EMPTY_BLAME);
- return Promise.reject(MSG_EMPTY_BLAME);
+ fireAlert(this, EMPTY_BLAME);
+ return Promise.reject(EMPTY_BLAME);
}
this._blame = blame;
@@ -730,14 +730,15 @@
}
_threadsChanged(threads: CommentThread[]) {
- // Currently, the only way this is ever changed here is when the initial
- // threads are loaded, so it's okay performance wise to clear the threads
- // and recreate them. If this changes in future, we might want to reuse
- // some DOM nodes here.
- this._clearThreads();
+ const threadEls = new Set<Object>();
for (const thread of threads) {
- const threadEl = this._createThreadElement(thread);
- this._attachThreadElement(threadEl);
+ threadEls.add(this._getOrCreateThread(thread));
+ }
+ // Remove all threads that are no longer existing.
+ for (const threadEl of this.getThreadEls()) {
+ if (threadEls.has(threadEl)) continue;
+ const parent = threadEl.parentNode;
+ if (parent) parent.removeChild(threadEl);
}
const portedThreadsCount = threads.filter(thread => thread.ported).length;
const portedThreadsWithoutRange = threads.filter(
@@ -786,14 +787,15 @@
? CommentSide.PARENT
: CommentSide.REVISION;
if (!this.canCommentOnPatchSetNum(patchNum)) return;
- const threadEl = this._getOrCreateThread(
- patchNum,
- lineNum,
- side,
- commentSide,
+ const threadEl = this._getOrCreateThread({
+ comments: [],
path,
- range
- );
+ diffSide: side,
+ commentSide,
+ patchNum,
+ line: lineNum,
+ range,
+ });
threadEl.addOrEditDraft(lineNum, range);
this.reporting.recordDraftInteraction();
@@ -829,26 +831,13 @@
* Gets or creates a comment thread at a given location.
* May provide a range, to get/create a range comment.
*/
- _getOrCreateThread(
- patchNum: PatchSetNum,
- lineNum: LineNumber | undefined,
- diffSide: Side,
- commentSide: CommentSide,
- path: string,
- range?: CommentRange
- ): GrCommentThread {
- let threadEl = this._getThreadEl(lineNum, diffSide, range);
+ _getOrCreateThread(thread: CommentThread): GrCommentThread {
+ let threadEl = this._getThreadEl(thread);
if (!threadEl) {
- threadEl = this._createThreadElement({
- comments: [],
- path,
- diffSide,
- commentSide,
- patchNum,
- line: lineNum,
- range,
- });
+ threadEl = this._createThreadElement(thread);
this._attachThreadElement(threadEl);
+ } else {
+ this._updateThreadElement(threadEl, thread);
}
return threadEl;
}
@@ -871,6 +860,11 @@
'slot',
`${thread.diffSide}-${thread.line || 'LOST'}`
);
+ this._updateThreadElement(threadEl, thread);
+ return threadEl;
+ }
+
+ _updateThreadElement(threadEl: GrCommentThread, thread: CommentThread) {
threadEl.comments = thread.comments;
threadEl.diffSide = thread.diffSide;
threadEl.isOnParent = thread.commentSide === CommentSide.PARENT;
@@ -896,34 +890,29 @@
else threadEl.lineNum = thread.line !== 'FILE' ? thread.line : undefined;
threadEl.projectName = this.projectName;
threadEl.range = thread.range;
- return threadEl;
}
/**
* Gets a comment thread element at a given location.
* May provide a range, to get a range comment.
*/
- _getThreadEl(
- lineNum: LineNumber | undefined,
- commentSide: Side,
- range?: CommentRange
- ): GrCommentThread | null {
+ _getThreadEl(thread: CommentThread): GrCommentThread | null {
let line: LineInfo;
- if (commentSide === Side.LEFT) {
- line = {beforeNumber: lineNum};
- } else if (commentSide === Side.RIGHT) {
- line = {afterNumber: lineNum};
+ if (thread.diffSide === Side.LEFT) {
+ line = {beforeNumber: thread.line};
+ } else if (thread.diffSide === Side.RIGHT) {
+ line = {afterNumber: thread.line};
} else {
- throw new Error(`Unknown side: ${commentSide}`);
+ throw new Error(`Unknown side: ${thread.diffSide}`);
}
function matchesRange(threadEl: GrCommentThread) {
- return rangesEqual(getRange(threadEl), range);
+ return rangesEqual(getRange(threadEl), thread.range);
}
const filteredThreadEls = this._filterThreadElsForLocation(
this.getThreadEls(),
line,
- commentSide
+ thread.diffSide
).filter(matchesRange);
return filteredThreadEls.length ? filteredThreadEls[0] : null;
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
index 42aa160..344f9d8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
@@ -23,7 +23,11 @@
import {Side, createDefaultDiffPrefs} from '../../../constants/constants.js';
import {createChange} from '../../../test/test-data-generators.js';
import {CoverageType} from '../../../types/types.js';
-import {addListenerForTest, stubRestApi} from '../../../test/test-utils.js';
+import {
+ addListenerForTest,
+ mockPromise,
+ stubRestApi,
+} from '../../../test/test-utils.js';
import {EditPatchSetNum, ParentPatchSetNum} from '../../../types/common.js';
import {_testOnly_resetState} from '../../../services/comments/comments-model.js';
@@ -64,14 +68,13 @@
});
suite('render reporting', () => {
- test('starts total and content timer on render-start', done => {
+ test('starts total and content timer on render-start', () => {
element.dispatchEvent(
new CustomEvent('render-start', {bubbles: true, composed: true}));
assert.isTrue(element.reporting.time.calledWithExactly(
'Diff Total Render'));
assert.isTrue(element.reporting.time.calledWithExactly(
'Diff Content Render'));
- done();
});
test('ends content timer on render-content', () => {
@@ -215,25 +218,23 @@
});
});
- test('prefetch getDiff', done => {
+ test('prefetch getDiff', async () => {
const diffRestApiStub = stubRestApi('getDiff')
.returns(Promise.resolve({content: []}));
element.changeNum = 123;
element.patchRange = {basePatchNum: 1, patchNum: 2};
element.path = 'file.txt';
element.prefetchDiff();
- element._getDiff().then(() =>{
- assert.isTrue(diffRestApiStub.calledOnce);
- done();
- });
+ await element._getDiff();
+ assert.isTrue(diffRestApiStub.calledOnce);
});
- test('_getDiff handles null diff responses', done => {
+ test('_getDiff handles null diff responses', async () => {
stubRestApi('getDiff').returns(Promise.resolve(null));
element.changeNum = 123;
element.patchRange = {basePatchNum: 1, patchNum: 2};
element.path = 'file.txt';
- element._getDiff().then(done);
+ await element._getDiff();
});
test('reload resolves on error', () => {
@@ -311,7 +312,7 @@
};
});
- test('renders image diffs with same file name', done => {
+ test('renders image diffs with same file name', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
@@ -342,6 +343,7 @@
},
}));
+ const promise = mockPromise();
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -377,7 +379,7 @@
leftLoaded = true;
if (rightLoaded) {
element.removeEventListener('render', rendered);
- done();
+ promise.resolve();
}
});
@@ -390,7 +392,7 @@
rightLoaded = true;
if (leftLoaded) {
element.removeEventListener('render', rendered);
- done();
+ promise.resolve();
}
});
};
@@ -398,9 +400,10 @@
element.addEventListener('render', rendered);
element.prefs = createDefaultDiffPrefs();
element.reload();
+ await promise;
});
- test('renders image diffs with a different file name', done => {
+ test('renders image diffs with a different file name', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg',
@@ -431,6 +434,7 @@
},
}));
+ const promise = mockPromise();
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -468,7 +472,7 @@
leftLoaded = true;
if (rightLoaded) {
element.removeEventListener('render', rendered);
- done();
+ promise.resolve();
}
});
@@ -481,7 +485,7 @@
rightLoaded = true;
if (leftLoaded) {
element.removeEventListener('render', rendered);
- done();
+ promise.resolve();
}
});
};
@@ -489,9 +493,10 @@
element.addEventListener('render', rendered);
element.prefs = createDefaultDiffPrefs();
element.reload();
+ await promise;
});
- test('renders added image', done => {
+ test('renders added image', async () => {
const mockDiff = {
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
@@ -517,6 +522,7 @@
},
}));
+ const promise = mockPromise();
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -530,14 +536,15 @@
assert.isNotOk(leftImage);
assert.isOk(rightImage);
- done();
+ promise.resolve();
});
element.prefs = createDefaultDiffPrefs();
element.reload();
+ await promise;
});
- test('renders removed image', done => {
+ test('renders removed image', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
@@ -563,6 +570,7 @@
revisionImage: null,
}));
+ const promise = mockPromise();
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -576,14 +584,15 @@
assert.isOk(leftImage);
assert.isNotOk(rightImage);
- done();
+ promise.resolve();
});
element.prefs = createDefaultDiffPrefs();
element.reload();
+ await promise;
});
- test('does not render disallowed image type', done => {
+ test('does not render disallowed image type', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil',
lines: 560},
@@ -611,6 +620,7 @@
revisionImage: null,
}));
+ const promise = mockPromise();
element.addEventListener('render', () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -619,11 +629,12 @@
const leftImage =
element.$.diff.$.diffTable.querySelector('td.left img');
assert.isNotOk(leftImage);
- done();
+ promise.resolve();
});
element.prefs = createDefaultDiffPrefs();
element.reload();
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts
index cf825ff..496d6bf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-image-viewer.ts
@@ -28,18 +28,10 @@
import {GrLibLoader} from '../../shared/gr-lib-loader/gr-lib-loader';
import {RESEMBLEJS_LIBRARY_CONFIG} from '../../shared/gr-lib-loader/resemblejs_config';
-import {
- css,
- customElement,
- html,
- LitElement,
- property,
- PropertyValues,
- query,
- state,
-} from 'lit-element';
-import {classMap} from 'lit-html/directives/class-map';
-import {StyleInfo, styleMap} from 'lit-html/directives/style-map';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {customElement, property, query, state} from 'lit/decorators';
+import {classMap} from 'lit/directives/class-map';
+import {StyleInfo, styleMap} from 'lit/directives/style-map';
import {
createEvent,
@@ -437,6 +429,11 @@
id="highlight-image"
style="${styleMap({
opacity: this.showHighlight ? '1' : '0',
+ // When the highlight layer is not being shown, saving the image or
+ // opening it in a new tab from the context menu, e.g. for external
+ // comparison, should give back the source image, not the highlight
+ // layer.
+ 'pointer-events': this.showHighlight ? 'auto' : 'none',
})}"
src="${this.diffHighlightSrc}"
/>
@@ -582,6 +579,7 @@
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
paper-item {
@@ -651,7 +649,9 @@
// We don't want property changes in updateSizes() to trigger infinite update
// loops, so we perform this in update() instead of updated().
override update(changedProperties: PropertyValues) {
+ // eslint-disable-next-line lit/no-property-change-update
if (!this.baseUrl) this.baseSelected = false;
+ // eslint-disable-next-line lit/no-property-change-update
if (!this.revisionUrl) this.baseSelected = true;
this.updateSizes();
super.update(changedProperties);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
index b1ea72f..28e6d82 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-overview-image.ts
@@ -14,17 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {
- css,
- customElement,
- html,
- LitElement,
- property,
- PropertyValues,
- query,
- state,
-} from 'lit-element';
-import {StyleInfo, styleMap} from 'lit-html/directives/style-map';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {customElement, property, query, state} from 'lit/decorators';
+import {StyleInfo, styleMap} from 'lit/directives/style-map';
import {ImageDiffAction} from '../../../api/diff';
import {createEvent, Dimensions, fitToFrame, Point, Rect} from './util';
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-zoomed-image.ts b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-zoomed-image.ts
index 671b858..66d4671 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-zoomed-image.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-image-viewer/gr-zoomed-image.ts
@@ -14,16 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {
- css,
- customElement,
- html,
- LitElement,
- property,
- PropertyValues,
- state,
-} from 'lit-element';
-import {StyleInfo, styleMap} from 'lit-html/directives/style-map';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
+import {StyleInfo, styleMap} from 'lit/directives/style-map';
import {Rect} from './util';
/**
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
index 4e2b6a1..8a6d95d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
@@ -30,28 +30,34 @@
width: 1.3rem;
}
</style>
- <gr-button
- id="sideBySideBtn"
- link=""
+ <gr-tooltip-content
has-tooltip=""
- position-below="[[showTooltipBelow]]"
- class$="[[_computeSideBySideSelected(mode)]]"
title="Side-by-side diff"
- aria-pressed$="[[isSideBySideSelected(mode)]]"
- on-click="_handleSideBySideTap"
+ position-below="[[showTooltipBelow]]"
>
- <iron-icon icon="gr-icons:side-by-side"></iron-icon>
- </gr-button>
- <gr-button
- id="unifiedBtn"
- link=""
+ <gr-button
+ id="sideBySideBtn"
+ link=""
+ class$="[[_computeSideBySideSelected(mode)]]"
+ aria-pressed$="[[isSideBySideSelected(mode)]]"
+ on-click="_handleSideBySideTap"
+ >
+ <iron-icon icon="gr-icons:side-by-side"></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>
+ <gr-tooltip-content
has-tooltip=""
position-below="[[showTooltipBelow]]"
title="Unified diff"
- class$="[[_computeUnifiedSelected(mode)]]"
- aria-pressed$="[[isUnifiedSelected(mode)]]"
- on-click="_handleUnifiedTap"
>
- <iron-icon icon="gr-icons:unified"></iron-icon>
- </gr-button>
+ <gr-button
+ id="unifiedBtn"
+ link=""
+ class$="[[_computeUnifiedSelected(mode)]]"
+ aria-pressed$="[[isUnifiedSelected(mode)]]"
+ on-click="_handleUnifiedTap"
+ >
+ <iron-icon icon="gr-icons:unified"></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>
`;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
index 787fe30..85edc12 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-preferences-dialog/gr-diff-preferences-dialog_html.ts
@@ -49,12 +49,12 @@
</style>
<gr-overlay id="diffPrefsOverlay" with-backdrop="">
<div role="dialog" aria-labelledby="diffPreferencesTitle">
- <h1
- class$="diffHeader [[_computeHeaderClass(_diffPrefsChanged)]]"
+ <h3
+ class$="heading-3 diffHeader [[_computeHeaderClass(_diffPrefsChanged)]]"
id="diffPreferencesTitle"
>
Diff Preferences
- </h1>
+ </h3>
<gr-diff-preferences
id="diffPreferences"
diff-prefs="{{_editableDiffPrefs}}"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
index 0051b8b..2665ef0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection.ts
@@ -195,7 +195,7 @@
_getSelection() {
const diffHosts = querySelectorAll(document.body, 'gr-diff');
- if (!diffHosts.length) return window.getSelection();
+ if (!diffHosts.length) return document.getSelection();
const curDiffHost = diffHosts.find(diffHost => {
if (!diffHost?.shadowRoot?.getSelection) return false;
@@ -205,9 +205,9 @@
return selection && selection.type !== 'None';
});
- return curDiffHost
- ? curDiffHost.shadowRoot!.getSelection()
- : window.getSelection();
+ return curDiffHost?.shadowRoot?.getSelection
+ ? curDiffHost.shadowRoot.getSelection()
+ : document.getSelection();
}
/**
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
index 8d7264c..15454f9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-selection/gr-diff-selection_test.js
@@ -247,7 +247,7 @@
element.classList.add('selected-left');
element.classList.remove('selected-right');
- const selection = window.getSelection();
+ const selection = document.getSelection();
selection.removeAllRanges();
const range = document.createRange();
range.setStart(element.querySelector('div.contentText').firstChild, 3);
@@ -261,7 +261,7 @@
element.classList.add('selected-left');
element.classList.add('selected-comment');
element.classList.remove('selected-right');
- const selection = window.getSelection();
+ const selection = document.getSelection();
selection.removeAllRanges();
const range = document.createRange();
range.setStart(
@@ -277,7 +277,7 @@
element.classList.add('selected-left');
element.classList.add('selected-comment');
element.classList.remove('selected-right');
- const selection = window.getSelection();
+ const selection = document.getSelection();
selection.removeAllRanges();
const range = document.createRange();
const nodes = element.querySelectorAll('.gr-formatted-text *');
@@ -307,7 +307,7 @@
element.classList.add('selected-right');
element.classList.remove('selected-left');
- const selection = window.getSelection();
+ const selection = document.getSelection();
selection.removeAllRanges();
const range = document.createRange();
range.setStart(
@@ -329,7 +329,7 @@
};
element.classList.add('selected-left');
element.classList.remove('selected-right');
- const selection = window.getSelection();
+ const selection = document.getSelection();
selection.removeAllRanges();
const range = document.createRange();
range.setStart(element.querySelector('div.contentText').firstChild, 3);
@@ -348,7 +348,7 @@
element.classList.add('selected-left');
element.classList.add('selected-comment');
element.classList.remove('selected-right');
- selection = window.getSelection();
+ selection = document.getSelection();
selection.removeAllRanges();
range = document.createRange();
nodes = element.querySelectorAll('.gr-formatted-text *');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 61259d1..bb5ce94 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-dropdown/iron-dropdown';
import '@polymer/iron-input/iron-input';
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
import '../../shared/gr-dropdown/gr-dropdown';
@@ -112,8 +113,8 @@
import {Subject} from 'rxjs';
const ERR_REVIEW_STATUS = 'Couldn’t change file review status.';
-const MSG_LOADING_BLAME = 'Loading blame...';
-const MSG_LOADED_BLAME = 'Blame loaded';
+const LOADING_BLAME = 'Loading blame...';
+const LOADED_BLAME = 'Blame loaded';
// Time in which pressing n key again after the toast navigates to next file
const NAVIGATE_TO_NEXT_FILE_TIMEOUT_MS = 5000;
@@ -140,8 +141,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-diff-view')
-export class GrDiffView extends KeyboardShortcutMixin(PolymerElement) {
+export class GrDiffView extends base {
static get template() {
return htmlTemplate;
}
@@ -1664,12 +1668,12 @@
_loadBlame() {
this._isBlameLoading = true;
- fireAlert(this, MSG_LOADING_BLAME);
+ fireAlert(this, LOADING_BLAME);
this.$.diffHost
.loadBlame()
.then(() => {
this._isBlameLoading = false;
- fireAlert(this, MSG_LOADED_BLAME);
+ fireAlert(this, LOADED_BLAME);
})
.catch(() => {
this._isBlameLoading = false;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
index 7e0ca10..4f1047f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
display: block;
@@ -351,15 +354,15 @@
hidden=""
>
<span class="preferences desktop">
- <gr-button
- link=""
- class="prefsButton"
+ <gr-tooltip-content
has-tooltip=""
position-below=""
title="Diff preferences"
- on-click="_handlePrefsTap"
- ><iron-icon icon="gr-icons:settings"></iron-icon
- ></gr-button>
+ >
+ <gr-button link="" class="prefsButton" on-click="_handlePrefsTap"
+ ><iron-icon icon="gr-icons:settings"></iron-icon
+ ></gr-button>
+ </gr-tooltip-content>
</span>
</span>
<gr-endpoint-decorator name="annotation-toggler">
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
index 033b886..a3de30a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
@@ -29,7 +29,6 @@
createComment,
} from '../../../test/test-data-generators.js';
import {EditPatchSetNum} from '../../../types/common.js';
-import sinon from 'sinon/pkg/sinon-esm';
import {CursorMoveResult} from '../../../api/core.js';
const basicFixture = fixtureFromElement('gr-diff-view');
@@ -678,23 +677,21 @@
assert.isNotOk(args[3]);
});
- test('A fires an error event when not logged in', done => {
+ test('A fires an error event when not logged in', async () => {
const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(false));
const loggedInErrorSpy = sinon.spy();
element.addEventListener('show-auth-required', loggedInErrorSpy);
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
- 'should only work when the user is logged in.');
- assert.isNull(window.sessionStorage.getItem(
- 'changeView.showReplyDialog'));
- assert.isTrue(loggedInErrorSpy.called);
- done();
- });
+ await flush();
+ assert.isTrue(changeNavStub.notCalled, 'The `a` keyboard shortcut ' +
+ 'should only work when the user is logged in.');
+ assert.isNull(window.sessionStorage.getItem(
+ 'changeView.showReplyDialog'));
+ assert.isTrue(loggedInErrorSpy.called);
});
- test('A navigates to change with logged in', done => {
+ test('A navigates to change with logged in', async () => {
element._changeNum = '42';
element._patchRange = {
basePatchNum: 5,
@@ -712,41 +709,38 @@
const loggedInErrorSpy = sinon.spy();
element.addEventListener('show-auth-required', loggedInErrorSpy);
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isTrue(element.changeViewState.showReplyDialog);
- assert(changeNavStub.lastCall.calledWithExactly(element._change, 10,
- 5), 'Should navigate to /c/42/5..10');
- assert.isFalse(loggedInErrorSpy.called);
- done();
- });
+ await flush();
+ assert.isTrue(element.changeViewState.showReplyDialog);
+ assert(changeNavStub.lastCall.calledWithExactly(element._change, 10,
+ 5), 'Should navigate to /c/42/5..10');
+ assert.isFalse(loggedInErrorSpy.called);
});
- test('A navigates to change with old patch number with logged in', done => {
- element._changeNum = '42';
- element._patchRange = {
- basePatchNum: PARENT,
- patchNum: 1,
- };
- element._change = {
- _number: 42,
- revisions: {
- a: {_number: 1, commit: {parents: []}},
- b: {_number: 2, commit: {parents: []}},
- },
- };
- const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
- sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
- const loggedInErrorSpy = sinon.spy();
- element.addEventListener('show-auth-required', loggedInErrorSpy);
- MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
- flush(() => {
- assert.isTrue(element.changeViewState.showReplyDialog);
- assert(changeNavStub.lastCall.calledWithExactly(element._change, 1,
- PARENT), 'Should navigate to /c/42/1');
- assert.isFalse(loggedInErrorSpy.called);
- done();
- });
- });
+ test('A navigates to change with old patch number with logged in',
+ async () => {
+ element._changeNum = '42';
+ element._patchRange = {
+ basePatchNum: PARENT,
+ patchNum: 1,
+ };
+ element._change = {
+ _number: 42,
+ revisions: {
+ a: {_number: 1, commit: {parents: []}},
+ b: {_number: 2, commit: {parents: []}},
+ },
+ };
+ const changeNavStub = sinon.stub(GerritNav, 'navigateToChange');
+ sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
+ const loggedInErrorSpy = sinon.spy();
+ element.addEventListener('show-auth-required', loggedInErrorSpy);
+ MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
+ await flush();
+ assert.isTrue(element.changeViewState.showReplyDialog);
+ assert(changeNavStub.lastCall.calledWithExactly(element._change, 1,
+ PARENT), 'Should navigate to /c/42/1');
+ assert.isFalse(loggedInErrorSpy.called);
+ });
test('keyboard shortcuts with patch range', () => {
element._changeNum = '42';
@@ -860,7 +854,7 @@
assert.isTrue(changeNavStub.calledOnce);
});
- test('edit should redirect to edit page', done => {
+ test('edit should redirect to edit page', async () => {
element._loggedIn = true;
element._path = 't.txt';
element._patchRange = {
@@ -877,23 +871,21 @@
},
};
const redirectStub = sinon.stub(GerritNav, 'navigateToRelativeUrl');
- flush(() => {
- const editBtn = element.shadowRoot
- .querySelector('.editButton gr-button');
- assert.isTrue(!!editBtn);
- MockInteractions.tap(editBtn);
- assert.isTrue(redirectStub.called);
- assert.isTrue(redirectStub.lastCall.calledWithExactly(
- GerritNav.getEditUrlForDiff(
- element._change,
- element._path,
- element._patchRange.patchNum
- )));
- done();
- });
+ await flush();
+ const editBtn = element.shadowRoot
+ .querySelector('.editButton gr-button');
+ assert.isTrue(!!editBtn);
+ MockInteractions.tap(editBtn);
+ assert.isTrue(redirectStub.called);
+ assert.isTrue(redirectStub.lastCall.calledWithExactly(
+ GerritNav.getEditUrlForDiff(
+ element._change,
+ element._path,
+ element._patchRange.patchNum
+ )));
});
- test('edit should redirect to edit page with line number', done => {
+ test('edit should redirect to edit page with line number', async () => {
const lineNumber = 42;
element._loggedIn = true;
element._path = 't.txt';
@@ -913,21 +905,19 @@
sinon.stub(element.cursor, 'getAddress')
.returns({number: lineNumber, isLeftSide: false});
const redirectStub = sinon.stub(GerritNav, 'navigateToRelativeUrl');
- flush(() => {
- const editBtn = element.shadowRoot
- .querySelector('.editButton gr-button');
- assert.isTrue(!!editBtn);
- MockInteractions.tap(editBtn);
- assert.isTrue(redirectStub.called);
- assert.isTrue(redirectStub.lastCall.calledWithExactly(
- GerritNav.getEditUrlForDiff(
- element._change,
- element._path,
- element._patchRange.patchNum,
- lineNumber
- )));
- done();
- });
+ await flush();
+ const editBtn = element.shadowRoot
+ .querySelector('.editButton gr-button');
+ assert.isTrue(!!editBtn);
+ MockInteractions.tap(editBtn);
+ assert.isTrue(redirectStub.called);
+ assert.isTrue(redirectStub.lastCall.calledWithExactly(
+ GerritNav.getEditUrlForDiff(
+ element._change,
+ element._path,
+ element._patchRange.patchNum,
+ lineNumber
+ )));
});
function isEditVisibile({loggedIn, changeStatus}) {
@@ -1294,7 +1284,7 @@
assert.isFalse(saveReviewedStub.called);
});
- test('hash is determined from params', done => {
+ test('hash is determined from params', async () => {
sinon.stub(element.$.diffHost, 'reload');
sinon.stub(element, '_initLineOfInterestAndCursor');
@@ -1308,10 +1298,8 @@
hash: 10,
};
- flush(() => {
- assert.isTrue(element._initLineOfInterestAndCursor.calledOnce);
- done();
- });
+ await flush();
+ assert.isTrue(element._initLineOfInterestAndCursor.calledOnce);
});
test('diff mode selector correctly toggles the diff', () => {
@@ -1360,15 +1348,13 @@
assert.equal(element._getDiffViewMode(), 'SIDE_BY_SIDE');
});
- test('diff mode selector should be hidden for binary', done => {
+ test('diff mode selector should be hidden for binary', async () => {
element._diff = {binary: true, content: []};
- flush(() => {
- const diffModeSelector = element.shadowRoot
- .querySelector('.diffModeSelector');
- assert.isTrue(diffModeSelector.classList.contains('hide'));
- done();
- });
+ await flush();
+ const diffModeSelector = element.shadowRoot
+ .querySelector('.diffModeSelector');
+ assert.isTrue(diffModeSelector.classList.contains('hide'));
});
suite('_commitRange', () => {
@@ -1400,7 +1386,7 @@
change));
});
- test('uses the patchNum and basePatchNum ', done => {
+ test('uses the patchNum and basePatchNum ', async () => {
element.params = {
view: GerritNav.View.DIFF,
changeNum: '42',
@@ -1409,16 +1395,14 @@
path: '/COMMIT_MSG',
};
element._change = change;
- flush(() => {
- assert.deepEqual(element._commitRange, {
- baseCommit: 'commit-sha-2',
- commit: 'commit-sha-4',
- });
- done();
+ await flush();
+ assert.deepEqual(element._commitRange, {
+ baseCommit: 'commit-sha-2',
+ commit: 'commit-sha-4',
});
});
- test('uses the parent when there is no base patch num ', done => {
+ test('uses the parent when there is no base patch num ', async () => {
element.params = {
view: GerritNav.View.DIFF,
changeNum: '42',
@@ -1426,12 +1410,10 @@
path: '/COMMIT_MSG',
};
element._change = change;
- flush(() => {
- assert.deepEqual(element._commitRange, {
- commit: 'commit-sha-5',
- baseCommit: 'sha-5-parent',
- });
- done();
+ await flush();
+ assert.deepEqual(element._commitRange, {
+ commit: 'commit-sha-5',
+ baseCommit: 'sha-5-parent',
});
});
});
@@ -1921,7 +1903,7 @@
]);
});
- test('File change should trigger navigateToDiff once', done => {
+ test('File change should trigger navigateToDiff once', async () => {
element._files = getFilesFromFileList(['file1', 'file2', 'file3']);
sinon.stub(element, '_initLineOfInterestAndCursor');
sinon.stub(GerritNav, 'navigateToDiff');
@@ -1942,7 +1924,7 @@
...createChange(),
revisions: createRevisions(1),
};
- flush();
+ await flush();
assert.isTrue(GerritNav.navigateToDiff.notCalled);
// Switch to file2
@@ -1964,7 +1946,6 @@
// No extra call
assert.isTrue(GerritNav.navigateToDiff.calledOnce);
- done();
});
test('_computeDownloadDropdownLinks', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
index fada9cb..7393606 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff-utils.ts
@@ -129,6 +129,29 @@
rootId: string;
}
+const VISIBLE_TEXT_NODE_TYPES = [Node.TEXT_NODE, Node.ELEMENT_NODE];
+
+export function getPreviousContentNodes(node?: Node | null) {
+ const sibs = [];
+ while (node) {
+ const {parentNode, previousSibling} = node;
+ const topContentLevel =
+ parentNode &&
+ (parentNode as HTMLElement).classList.contains('contentText');
+ let previousEl: Node | undefined | null;
+ if (previousSibling) {
+ previousEl = previousSibling;
+ } else if (!topContentLevel) {
+ previousEl = parentNode?.previousSibling;
+ }
+ if (previousEl && VISIBLE_TEXT_NODE_TYPES.includes(previousEl.nodeType)) {
+ sibs.push(previousEl);
+ }
+ node = previousEl;
+ }
+ return sibs;
+}
+
export function isThreadEl(node: Node): node is GrDiffThreadElement {
return (
node.nodeType === Node.ELEMENT_NODE &&
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
index 9fb2a19..7efd2f8 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.ts
@@ -85,6 +85,7 @@
import {
DiffContextExpandedEventDetail,
getResponsiveMode,
+ isResponsive,
} from '../gr-diff-builder/gr-diff-builder';
const NO_NEWLINE_BASE = 'No newline at end of base file.';
@@ -754,8 +755,7 @@
const stylesToUpdate: {[key: string]: string} = {};
const responsiveMode = getResponsiveMode(prefs, renderPrefs);
- const responsive =
- responsiveMode === 'FULL_RESPONSIVE' || responsiveMode === 'SHRINK_ONLY';
+ const responsive = isResponsive(responsiveMode);
this._diffTableClass = responsive ? 'responsive' : '';
const lineLimit = `${lineLength}ch`;
stylesToUpdate['--line-limit-marker'] =
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
index 79ef38a..83b0aad 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_html.ts
@@ -69,10 +69,9 @@
/* Provides the option to add side borders (left and right) to the line number column. */
td.left,
td.right,
+ td.moveControlsLineNumCol,
td.contextLineNum {
- border-width: var(--line-number-border-width, 0);
- border-style: solid;
- border-color: var(--line-number-border-color, var(--border-color, unset));
+ box-shadow: var(--line-number-box-shadow, unset);
}
/*
@@ -112,6 +111,7 @@
width: 100%;
height: 100%;
background-color: var(--diff-blank-background-color);
+ box-shadow: var(--line-number-box-shadow, unset);
}
td.lineNum {
vertical-align: top;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
index c59ceb7..9ee779c 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.js
@@ -23,7 +23,7 @@
import {_setHiddenScroll} from '../../../scripts/hiddenscroll.js';
import {runA11yAudit} from '../../../test/a11y-test-utils.js';
import '@polymer/paper-button/paper-button.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {mockPromise, stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-diff');
@@ -232,7 +232,9 @@
};
});
- test('renders image diffs with same file name', done => {
+ test('renders image diffs with same file name', async () => {
+ const leftRendered = mockPromise();
+ const rightRendered = mockPromise();
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -256,19 +258,12 @@
assert.isNotOk(rightLabelName);
assert.isNotOk(leftLabelName);
- let leftLoaded = false;
- let rightLoaded = false;
-
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
- leftLoaded = true;
- if (rightLoaded) {
- element.removeEventListener('render', rendered);
- done();
- }
+ leftRendered.resolve();
});
rightImage.addEventListener('load', () => {
@@ -277,11 +272,7 @@
'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
- rightLoaded = true;
- if (leftLoaded) {
- element.removeEventListener('render', rendered);
- done();
- }
+ rightRendered.resolve();
});
};
@@ -305,9 +296,11 @@
content: [{skip: 66}],
binary: true,
};
+ await Promise.all([leftRendered, rightRendered]);
+ element.removeEventListener('render', rendered);
});
- test('renders image diffs with a different file name', done => {
+ test('renders image diffs with a different file name', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg',
@@ -324,7 +317,8 @@
content: [{skip: 66}],
binary: true,
};
-
+ const leftRendered = mockPromise();
+ const rightRendered = mockPromise();
const rendered = () => {
// Recognizes that it should be an image diff.
assert.isTrue(element.isImageDiff);
@@ -350,19 +344,12 @@
assert.equal(leftLabelName.textContent, mockDiff.meta_a.name);
assert.equal(rightLabelName.textContent, mockDiff.meta_b.name);
- let leftLoaded = false;
- let rightLoaded = false;
-
leftImage.addEventListener('load', () => {
assert.isOk(leftImage);
assert.equal(leftImage.getAttribute('src'),
'data:image/bmp;base64,' + mockFile1.body);
assert.equal(leftLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
- leftLoaded = true;
- if (rightLoaded) {
- element.removeEventListener('render', rendered);
- done();
- }
+ leftRendered.resolve();
});
rightImage.addEventListener('load', () => {
@@ -371,11 +358,7 @@
'data:image/bmp;base64,' + mockFile2.body);
assert.equal(rightLabelContent.textContent, '1\u00d71 image/bmp');// \u00d7 - '×'
- rightLoaded = true;
- if (leftLoaded) {
- element.removeEventListener('render', rendered);
- done();
- }
+ rightRendered.resolve();
});
};
@@ -386,9 +369,11 @@
element.revisionImage = mockFile2;
element.revisionImage._name = mockDiff.meta_b.name;
element.diff = mockDiff;
+ await Promise.all([leftRendered, rightRendered]);
+ element.removeEventListener('render', rendered);
});
- test('renders added image', done => {
+ test('renders added image', async () => {
const mockDiff = {
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
@@ -405,27 +390,27 @@
binary: true,
};
- function rendered() {
- // Recognizes that it should be an image diff.
- assert.isTrue(element.isImageDiff);
- assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
-
- const leftImage = element.$.diffTable.querySelector('td.left img');
- const rightImage = element.$.diffTable.querySelector('td.right img');
-
- assert.isNotOk(leftImage);
- assert.isOk(rightImage);
- done();
- element.removeEventListener('render', rendered);
- }
+ const promise = mockPromise();
+ function rendered() { promise.resolve(); }
element.addEventListener('render', rendered);
element.revisionImage = mockFile2;
element.diff = mockDiff;
+ await promise;
+ element.removeEventListener('render', rendered);
+ // Recognizes that it should be an image diff.
+ assert.isTrue(element.isImageDiff);
+ assert.instanceOf(
+ element.$.diffBuilder._builder, GrDiffBuilderImage);
+
+ const leftImage = element.$.diffTable.querySelector('td.left img');
+ const rightImage = element.$.diffTable.querySelector('td.right img');
+
+ assert.isNotOk(leftImage);
+ assert.isOk(rightImage);
});
- test('renders removed image', done => {
+ test('renders removed image', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg',
lines: 560},
@@ -441,28 +426,27 @@
content: [{skip: 66}],
binary: true,
};
-
- function rendered() {
- // Recognizes that it should be an image diff.
- assert.isTrue(element.isImageDiff);
- assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
-
- const leftImage = element.$.diffTable.querySelector('td.left img');
- const rightImage = element.$.diffTable.querySelector('td.right img');
-
- assert.isOk(leftImage);
- assert.isNotOk(rightImage);
- done();
- element.removeEventListener('render', rendered);
- }
+ const promise = mockPromise();
+ function rendered() { promise.resolve(); }
element.addEventListener('render', rendered);
element.baseImage = mockFile1;
element.diff = mockDiff;
+ await promise;
+ element.removeEventListener('render', rendered);
+ // Recognizes that it should be an image diff.
+ assert.isTrue(element.isImageDiff);
+ assert.instanceOf(
+ element.$.diffBuilder._builder, GrDiffBuilderImage);
+
+ const leftImage = element.$.diffTable.querySelector('td.left img');
+ const rightImage = element.$.diffTable.querySelector('td.right img');
+
+ assert.isOk(leftImage);
+ assert.isNotOk(rightImage);
});
- test('does not render disallowed image type', done => {
+ test('does not render disallowed image type', async () => {
const mockDiff = {
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil',
lines: 560},
@@ -480,50 +464,54 @@
};
mockFile1.type = 'image/jpeg-evil';
- function rendered() {
- // Recognizes that it should be an image diff.
- assert.isTrue(element.isImageDiff);
- assert.instanceOf(
- element.$.diffBuilder._builder, GrDiffBuilderImage);
- const leftImage = element.$.diffTable.querySelector('td.left img');
- assert.isNotOk(leftImage);
- done();
- element.removeEventListener('render', rendered);
- }
+ const promise = mockPromise();
+ function rendered() { promise.resolve(); }
element.addEventListener('render', rendered);
element.baseImage = mockFile1;
element.diff = mockDiff;
+ await promise;
+ element.removeEventListener('render', rendered);
+ // Recognizes that it should be an image diff.
+ assert.isTrue(element.isImageDiff);
+ assert.instanceOf(
+ element.$.diffBuilder._builder, GrDiffBuilderImage);
+ const leftImage = element.$.diffTable.querySelector('td.left img');
+ assert.isNotOk(leftImage);
});
});
- test('_handleTap lineNum', done => {
+ test('_handleTap lineNum', async () => {
const addDraftStub = sinon.stub(element, 'addDraftAtLine');
const el = document.createElement('div');
el.className = 'lineNum';
+ const promise = mockPromise();
el.addEventListener('click', e => {
element._handleTap(e);
assert.isTrue(addDraftStub.called);
assert.equal(addDraftStub.lastCall.args[0], el);
- done();
+ promise.resolve();
});
el.click();
+ await promise;
});
- test('_handleTap context', done => {
+ test('_handleTap context', async () => {
const showContextStub =
sinon.stub(element.$.diffBuilder, 'showContext');
const el = document.createElement('div');
el.className = 'showContext';
+ const promise = mockPromise();
el.addEventListener('click', e => {
element._handleDiffContextExpanded(e);
assert.isTrue(showContextStub.called);
- done();
+ promise.resolve();
});
el.click();
+ await promise;
});
- test('_handleTap content', done => {
+ test('_handleTap content', async () => {
const content = document.createElement('div');
const lineEl = document.createElement('div');
lineEl.className = 'lineNum';
@@ -534,13 +522,15 @@
const selectStub = sinon.stub(element, '_selectLine');
content.className = 'content';
+ const promise = mockPromise();
content.addEventListener('click', e => {
element._handleTap(e);
assert.isTrue(selectStub.called);
assert.equal(selectStub.lastCall.args[0], lineEl);
- done();
+ promise.resolve();
});
content.click();
+ await promise;
});
suite('getCursorStops', () => {
@@ -816,41 +806,47 @@
element.noRenderOnPrefsChange = true;
});
- test('large render w/ context = 10', done => {
+ test('large render w/ context = 10', async () => {
element.prefs = {...MINIMAL_PREFS, context: 10};
+ const promise = mockPromise();
function rendered() {
assert.isTrue(renderStub.called);
assert.isFalse(element._showWarning);
- done();
+ promise.resolve();
element.removeEventListener('render', rendered);
}
element.addEventListener('render', rendered);
element._renderDiffTable();
+ await promise;
});
- test('large render w/ whole file and bypass', done => {
+ test('large render w/ whole file and bypass', async () => {
element.prefs = {...MINIMAL_PREFS, context: -1};
element._safetyBypass = 10;
+ const promise = mockPromise();
function rendered() {
assert.isTrue(renderStub.called);
assert.isFalse(element._showWarning);
- done();
+ promise.resolve();
element.removeEventListener('render', rendered);
}
element.addEventListener('render', rendered);
element._renderDiffTable();
+ await promise;
});
- test('large render w/ whole file and no bypass', done => {
+ test('large render w/ whole file and no bypass', async () => {
element.prefs = {...MINIMAL_PREFS, context: -1};
+ const promise = mockPromise();
function rendered() {
assert.isFalse(renderStub.called);
assert.isTrue(element._showWarning);
- done();
+ promise.resolve();
element.removeEventListener('render', rendered);
}
element.addEventListener('render', rendered);
element._renderDiffTable();
+ await promise;
});
test('toggles expand context using bypass', async () => {
@@ -1219,16 +1215,18 @@
assert.equal(element.getDiffLength(diff), 52);
});
- test('`render` event has contentRendered field in detail', done => {
+ test('`render` event has contentRendered field in detail', async () => {
element = basicFixture.instantiate();
element.prefs = {};
sinon.stub(element.$.diffBuilder, 'render')
.returns(Promise.resolve());
+ const promise = mockPromise();
element.addEventListener('render', event => {
assert.isTrue(event.detail.contentRendered);
- done();
+ promise.resolve();
});
element._renderDiffTable();
+ await promise;
});
test('_prefsEqual', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
index 3544834..0d6cadc 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-dropdown-list/gr-dropdown-list';
import '../../shared/gr-select/gr-select';
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_html.ts b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_html.ts
index 5ab8449..ebbb0d6 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
align-items: center;
diff --git a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.js b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.js
index 89b8b4a..0fe1fe2 100644
--- a/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-patch-range-select/gr-patch-range-select_test.js
@@ -196,7 +196,7 @@
});
test('_computeBaseDropdownContent called when changeComments update',
- done => {
+ async () => {
element.revisions = [
{commit: {parents: []}},
{commit: {parents: []}},
@@ -212,15 +212,14 @@
];
element.patchNum = 2;
element.basePatchNum = 'PARENT';
- flush();
+ await flush();
// Should be recomputed for each available patch
sinon.stub(element, '_computeBaseDropdownContent');
assert.equal(element._computeBaseDropdownContent.callCount, 0);
element.changeComments = new ChangeComments();
- flush();
+ await flush();
assert.equal(element._computeBaseDropdownContent.callCount, 1);
- done();
});
test('_computePatchDropdownContent called when basePatchNum updates', () => {
diff --git a/polygerrit-ui/app/elements/diff/gr-range-header/gr-range-header.ts b/polygerrit-ui/app/elements/diff/gr-range-header/gr-range-header.ts
index 776b954..1c2c074 100644
--- a/polygerrit-ui/app/elements/diff/gr-range-header/gr-range-header.ts
+++ b/polygerrit-ui/app/elements/diff/gr-range-header/gr-range-header.ts
@@ -14,9 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
/**
* Represents a header (label) for a code chunk whenever showing
@@ -25,7 +24,7 @@
* like long comments and moved in/out chunks.
*/
@customElement('gr-range-header')
-export class GrRangeHeader extends GrLitElement {
+export class GrRangeHeader extends LitElement {
@property({type: String})
icon?: string;
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
index f82290b..3f2258d 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-hint/gr-ranged-comment-hint.ts
@@ -17,13 +17,13 @@
import '../gr-range-header/gr-range-header';
import {CommentRange} from '../../../types/common';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {sharedStyles} from '../../../styles/shared-styles';
import {grRangedCommentTheme} from '../gr-ranged-comment-themes/gr-ranged-comment-theme';
@customElement('gr-ranged-comment-hint')
-export class GrRangedCommentHint extends GrLitElement {
+export class GrRangedCommentHint extends LitElement {
@property({type: Object})
range?: CommentRange;
@@ -45,6 +45,7 @@
override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
.row {
diff --git a/polygerrit-ui/app/elements/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts b/polygerrit-ui/app/elements/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
index c3fadf5..fb20a91 100644
--- a/polygerrit-ui/app/elements/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
+++ b/polygerrit-ui/app/elements/diff/gr-ranged-comment-themes/gr-ranged-comment-theme.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
diff --git a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
index b8c3c16..c907a80 100644
--- a/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-syntax-layer/gr-syntax-layer_test.js
@@ -120,7 +120,7 @@
assert.isFalse(annotationSpy.called);
});
- test('process on empty diff does nothing', done => {
+ test('process on empty diff does nothing', async () => {
element.diff = {
meta_a: {content_type: 'application/json'},
meta_b: {content_type: 'application/json'},
@@ -128,17 +128,14 @@
};
const processNextSpy = sinon.spy(element, '_processNextLine');
- const processPromise = element.process();
+ await element.process();
- processPromise.then(() => {
- assert.isFalse(processNextSpy.called);
- assert.equal(element.baseRanges.length, 0);
- assert.equal(element.revisionRanges.length, 0);
- done();
- });
+ assert.isFalse(processNextSpy.called);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
});
- test('process for unsupported languages does nothing', done => {
+ test('process for unsupported languages does nothing', async () => {
element.diff = {
meta_a: {content_type: 'text/x+objective-cobol-plus-plus'},
meta_b: {content_type: 'application/not-a-real-language'},
@@ -146,33 +143,27 @@
};
const processNextSpy = sinon.spy(element, '_processNextLine');
- const processPromise = element.process();
+ await element.process();
- processPromise.then(() => {
- assert.isFalse(processNextSpy.called);
- assert.equal(element.baseRanges.length, 0);
- assert.equal(element.revisionRanges.length, 0);
- done();
- });
+ assert.isFalse(processNextSpy.called);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
});
- test('process while disabled does nothing', done => {
+ test('process while disabled does nothing', async () => {
const processNextSpy = sinon.spy(element, '_processNextLine');
element.enabled = false;
const loadHLJSSpy = sinon.spy(element, '_loadHLJS');
- const processPromise = element.process();
+ await element.process();
- processPromise.then(() => {
- assert.isFalse(processNextSpy.called);
- assert.equal(element.baseRanges.length, 0);
- assert.equal(element.revisionRanges.length, 0);
- assert.isFalse(loadHLJSSpy.called);
- done();
- });
+ assert.isFalse(processNextSpy.called);
+ assert.equal(element.baseRanges.length, 0);
+ assert.equal(element.revisionRanges.length, 0);
+ assert.isFalse(loadHLJSSpy.called);
});
- test('process highlight ipsum', done => {
+ test('process highlight ipsum', async () => {
element.diff.meta_a.content_type = 'application/json';
element.diff.meta_b.content_type = 'application/json';
@@ -180,65 +171,61 @@
window.hljs = mockHLJS;
const highlightSpy = sinon.spy(mockHLJS, 'highlight');
const processNextSpy = sinon.spy(element, '_processNextLine');
- const processPromise = element.process();
+ await element.process();
- processPromise.then(() => {
- const linesA = diff.meta_a.lines;
- const linesB = diff.meta_b.lines;
+ const linesA = diff.meta_a.lines;
+ const linesB = diff.meta_b.lines;
- assert.isTrue(processNextSpy.called);
- assert.equal(element.baseRanges.length, linesA);
- assert.equal(element.revisionRanges.length, linesB);
+ assert.isTrue(processNextSpy.called);
+ assert.equal(element.baseRanges.length, linesA);
+ assert.equal(element.revisionRanges.length, linesB);
- assert.equal(highlightSpy.callCount, linesA + linesB);
+ assert.equal(highlightSpy.callCount, linesA + linesB);
- // The first line of both sides have a range.
- let ranges = [element.baseRanges[0], element.revisionRanges[0]];
- for (const range of ranges) {
- assert.equal(range.length, 1);
- assert.equal(range[0].className,
- 'gr-diff gr-syntax gr-syntax-string');
- assert.equal(range[0].start, 'lorem '.length);
- assert.equal(range[0].length, 'ipsum'.length);
- }
-
- // There are no ranges from ll.1-12 on the left and ll.1-11 on the
- // right.
- ranges = element.baseRanges.slice(1, 12)
- .concat(element.revisionRanges.slice(1, 11));
-
- for (const range of ranges) {
- assert.equal(range.length, 0);
- }
-
- // There should be another pair of ranges on l.13 for the left and
- // l.12 for the right.
- ranges = [element.baseRanges[13], element.revisionRanges[12]];
-
- for (const range of ranges) {
- assert.equal(range.length, 1);
- assert.equal(range[0].className,
- 'gr-diff gr-syntax gr-syntax-string');
- assert.equal(range[0].start, 32);
- assert.equal(range[0].length, 'ipsum'.length);
- }
-
- // The next group should have a similar instance on either side.
-
- let range = element.baseRanges[15];
+ // The first line of both sides have a range.
+ let ranges = [element.baseRanges[0], element.revisionRanges[0]];
+ for (const range of ranges) {
assert.equal(range.length, 1);
- assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
- assert.equal(range[0].start, 34);
+ assert.equal(range[0].className,
+ 'gr-diff gr-syntax gr-syntax-string');
+ assert.equal(range[0].start, 'lorem '.length);
assert.equal(range[0].length, 'ipsum'.length);
+ }
- range = element.revisionRanges[14];
+ // There are no ranges from ll.1-12 on the left and ll.1-11 on the
+ // right.
+ ranges = element.baseRanges.slice(1, 12)
+ .concat(element.revisionRanges.slice(1, 11));
+
+ for (const range of ranges) {
+ assert.equal(range.length, 0);
+ }
+
+ // There should be another pair of ranges on l.13 for the left and
+ // l.12 for the right.
+ ranges = [element.baseRanges[13], element.revisionRanges[12]];
+
+ for (const range of ranges) {
assert.equal(range.length, 1);
- assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
- assert.equal(range[0].start, 35);
+ assert.equal(range[0].className,
+ 'gr-diff gr-syntax gr-syntax-string');
+ assert.equal(range[0].start, 32);
assert.equal(range[0].length, 'ipsum'.length);
+ }
- done();
- });
+ // The next group should have a similar instance on either side.
+
+ let range = element.baseRanges[15];
+ assert.equal(range.length, 1);
+ assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
+ assert.equal(range[0].start, 34);
+ assert.equal(range[0].length, 'ipsum'.length);
+
+ range = element.revisionRanges[14];
+ assert.equal(range.length, 1);
+ assert.equal(range[0].className, 'gr-diff gr-syntax gr-syntax-string');
+ assert.equal(range[0].start, 35);
+ assert.equal(range[0].length, 'ipsum'.length);
});
test('init calls cancel', () => {
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
index 90c8383..3adb0f3 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
@@ -19,18 +19,15 @@
import '../../shared/gr-list-view/gr-list-view';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-documentation-search_html';
-import {
- ListViewMixin,
- ListViewParams,
-} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {getBaseUrl} from '../../../utils/url-util';
import {customElement, property} from '@polymer/decorators';
import {DocResult} from '../../../types/common';
import {fireTitleChange} from '../../../utils/event-util';
import {appContext} from '../../../services/app-context';
+import {ListViewParams} from '../../gr-app-types';
@customElement('gr-documentation-search')
-export class GrDocumentationSearch extends ListViewMixin(PolymerElement) {
+export class GrDocumentationSearch extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -59,7 +56,7 @@
_paramsChanged(params: ListViewParams) {
this._loading = true;
- this._filter = this.getFilterValue(params);
+ this._filter = params?.filter ?? '';
return this._getDocumentationSearches(this._filter);
}
@@ -84,6 +81,10 @@
}
return `${getBaseUrl()}/${url}`;
}
+
+ computeLoadingClass(loading: boolean) {
+ return loading ? 'loading' : '';
+ }
}
declare global {
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.ts
index 9c196c7..bf6a0d5 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.ts
@@ -21,8 +21,8 @@
import {page} from '../../../utils/page-wrapper-utils';
import 'lodash/lodash';
import {stubRestApi} from '../../../test/test-utils';
-import {ListViewParams} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
import {DocResult} from '../../../types/common';
+import {ListViewParams} from '../../gr-app-types';
const basicFixture = fixtureFromElement('gr-documentation-search');
@@ -47,28 +47,24 @@
});
suite('list with searches for documentation', () => {
- setup(done => {
+ setup(async () => {
documentationSearches = _.times(26, documentationGenerator);
stubRestApi('getDocumentationSearches').returns(
Promise.resolve(documentationSearches)
);
- element._paramsChanged(value).then(() => {
- flush(done);
- });
+ await element._paramsChanged(value);
+ await flush();
});
- test('test for test repo in the list', done => {
- flush(() => {
- assert.equal(
- element._documentationSearches![0].title,
- 'Gerrit Code Review - REST API Developers Notes1'
- );
- assert.equal(
- element._documentationSearches![0].url,
- 'Documentation/dev-rest-api.html'
- );
- done();
- });
+ test('test for test repo in the list', async () => {
+ assert.equal(
+ element._documentationSearches![0].title,
+ 'Gerrit Code Review - REST API Developers Notes1'
+ );
+ assert.equal(
+ element._documentationSearches![0].url,
+ 'Documentation/dev-rest-api.html'
+ );
});
});
@@ -88,14 +84,14 @@
});
suite('loading', () => {
- test('correct contents are displayed', () => {
+ test('correct contents are displayed', async () => {
assert.isTrue(element._loading);
assert.equal(element.computeLoadingClass(element._loading), 'loading');
assert.equal(getComputedStyle(element.$.loading).display, 'block');
element._loading = false;
- flush();
+ await flush();
assert.equal(element.computeLoadingClass(element._loading), '');
assert.equal(getComputedStyle(element.$.loading).display, 'none');
});
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
index b04e6cf..480b8fe 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor.ts
@@ -16,8 +16,8 @@
*/
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -26,7 +26,7 @@
}
@customElement('gr-default-editor')
-export class GrDefaultEditor extends GrLitElement {
+export class GrDefaultEditor extends LitElement {
/**
* Fired when the content of the editor changes.
*
diff --git a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.ts b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.ts
index 8a483fc..6b7ce34 100644
--- a/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-default-editor/gr-default-editor_test.ts
@@ -18,7 +18,7 @@
import '../../../test/common-test-setup-karma';
import './gr-default-editor';
import {GrDefaultEditor} from './gr-default-editor';
-import {queryAndAssert} from '../../../test/test-utils';
+import {mockPromise, queryAndAssert} from '../../../test/test-utils';
const basicFixture = fixtureFromElement('gr-default-editor');
@@ -31,13 +31,15 @@
await flush();
});
- test('fires content-change event', done => {
+ test('fires content-change event', async () => {
const textarea = queryAndAssert<HTMLTextAreaElement>(element, '#textarea');
+ const promise = mockPromise();
element.addEventListener('content-change', e => {
assert.equal((e as CustomEvent).detail.value, 'test');
- done();
+ promise.resolve();
});
textarea.value = 'test';
textarea.dispatchEvent(new Event('input', {bubbles: true, composed: true}));
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
index 18e6e75..2e1fc21 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.ts
@@ -402,15 +402,13 @@
});
});
- test('openOpenDialog', done => {
- element.openOpenDialog('test/path.cpp').then(() => {
- assert.isFalse(element.$.openDialog.hasAttribute('hidden'));
- assert.equal(
- element.$.openDialog!.querySelector('gr-autocomplete')!.text,
- 'test/path.cpp'
- );
- done();
- });
+ test('openOpenDialog', async () => {
+ await element.openOpenDialog('test/path.cpp');
+ assert.isFalse(element.$.openDialog.hasAttribute('hidden'));
+ assert.equal(
+ element.$.openDialog!.querySelector('gr-autocomplete')!.text,
+ 'test/path.cpp'
+ );
});
test('_getDialogFromEvent', () => {
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
index ce4c313..db45c33 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-file-controls/gr-edit-file-controls.ts
@@ -18,8 +18,8 @@
import '../../shared/gr-dropdown/gr-dropdown';
import {GrEditConstants} from '../gr-edit-constants';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
interface EditAction {
label: string;
@@ -27,7 +27,7 @@
}
@customElement('gr-edit-file-controls')
-export class GrEditFileControls extends GrLitElement {
+export class GrEditFileControls extends LitElement {
/**
* Fired when an action in the overflow menu is tapped.
*
@@ -59,6 +59,7 @@
override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
gr-button,
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 f5dc610..6f2d27e 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
@@ -68,8 +68,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-editor-view')
-export class GrEditorView extends KeyboardShortcutMixin(PolymerElement) {
+export class GrEditorView extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
index 5b04a81..f591ab2 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.ts
@@ -19,7 +19,7 @@
import {GrEditorView} from './gr-editor-view';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {HttpMethod} from '../../../constants/constants';
-import {stubRestApi, stubStorage} from '../../../test/test-utils';
+import {mockPromise, stubRestApi, stubStorage} from '../../../test/test-utils';
import {
EditPatchSetNum,
NumericChangeId,
@@ -348,14 +348,16 @@
});
});
- test('_showAlert', done => {
+ test('_showAlert', async () => {
+ const promise = mockPromise();
element.addEventListener('show-alert', e => {
assert.deepEqual(e.detail, {message: 'test message'});
assert.isTrue(e.bubbles);
- done();
+ promise.resolve();
});
element._showAlert('test message');
+ await promise;
});
test('_viewEditInChangeView', () => {
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index 88ed0dc..b6fe60b 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -102,9 +102,12 @@
restamp: boolean;
};
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
// TODO(TS): implement AppElement interface from gr-app-types.ts
@customElement('gr-app-element')
-export class GrAppElement extends KeyboardShortcutMixin(PolymerElement) {
+export class GrAppElement extends base {
static get template() {
return htmlTemplate;
}
@@ -349,6 +352,8 @@
this.bindShortcut(Shortcut.TOGGLE_CHANGE_STAR, 's:keydown');
this.bindShortcut(Shortcut.REFRESH_CHANGE_LIST, 'shift+r:keyup');
this.bindShortcut(Shortcut.EDIT_TOPIC, 't');
+ this.bindShortcut(Shortcut.OPEN_SUBMIT_DIALOG, 'shift+s');
+ this.bindShortcut(Shortcut.TOGGLE_ATTENTION_SET, 'shift+t');
this.bindShortcut(Shortcut.OPEN_REPLY_DIALOG, 'a:keyup');
this.bindShortcut(Shortcut.OPEN_DOWNLOAD_DIALOG, 'd:keyup');
diff --git a/polygerrit-ui/app/elements/gr-app-types.ts b/polygerrit-ui/app/elements/gr-app-types.ts
index e5096c0..6c8bdb9 100644
--- a/polygerrit-ui/app/elements/gr-app-types.ts
+++ b/polygerrit-ui/app/elements/gr-app-types.ts
@@ -52,20 +52,21 @@
groupId: GroupId;
}
-export interface AppElementAdminParams {
+export interface ListViewParams {
+ filter?: string | null;
+ offset?: number | string;
+}
+
+export interface AppElementAdminParams extends ListViewParams {
view: GerritView.ADMIN;
adminView: string;
- offset?: string | number;
- filter?: string | null;
openCreateModal?: boolean;
}
-export interface AppElementRepoParams {
+export interface AppElementRepoParams extends ListViewParams {
view: GerritView.REPO;
detail?: RepoDetailView;
repo: RepoName;
- offset?: string | number;
- filter?: string | null;
}
export interface AppElementDocSearchParams {
diff --git a/polygerrit-ui/app/elements/lit/gr-lit-element.ts b/polygerrit-ui/app/elements/lit/gr-lit-element.ts
deleted file mode 100644
index d0b68e3..0000000
--- a/polygerrit-ui/app/elements/lit/gr-lit-element.ts
+++ /dev/null
@@ -1,52 +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 {LitElement} from 'lit-element';
-import {Observable, Subject} from 'rxjs';
-import {takeUntil} from 'rxjs/operators';
-
-/**
- * Base class for Gerrit's lit-elements.
- *
- * Adds basic functionality that we want to have available in all Gerrit's
- * components.
- */
-export abstract class GrLitElement extends LitElement {
- disconnected$ = new Subject();
-
- /**
- * Hooks up an element property with an observable. Apart from subscribing it
- * makes sure that you are unsubscribed when the component is disconnected.
- * And it requests a template check when a new value comes in.
- *
- * Should be called from connectedCallback() such that you will be
- * re-subscribed when the component is re-connected.
- *
- * TODO: Maybe distinctUntilChanged should be applied to obs$?
- */
- subscribe<Key extends keyof this>(prop: Key, obs$: Observable<this[Key]>) {
- obs$.pipe(takeUntil(this.disconnected$)).subscribe(value => {
- const oldValue = this[prop];
- this[prop] = value;
- this.requestUpdate(prop, oldValue);
- });
- }
-
- override disconnectedCallback() {
- this.disconnected$.next();
- super.disconnectedCallback();
- }
-}
diff --git a/polygerrit-ui/app/elements/lit/gr-lit-element_test.ts b/polygerrit-ui/app/elements/lit/gr-lit-element_test.ts
deleted file mode 100644
index 9b7b0e2..0000000
--- a/polygerrit-ui/app/elements/lit/gr-lit-element_test.ts
+++ /dev/null
@@ -1,40 +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 '../../test/common-test-setup-karma';
-import {html, customElement} from 'lit-element';
-import {GrLitElement} from './gr-lit-element';
-
-@customElement('test-gr-lit-element')
-export class TestGrLitElement extends GrLitElement {
- render() {
- return html`<span>test</span>`;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'test-gr-lit-element': GrLitElement;
- }
-}
-
-suite('gr-lit-element test', () => {
- test('is defined', () => {
- const el = document.createElement('test-gr-lit-element');
- assert.instanceOf(el, TestGrLitElement);
- });
-});
diff --git a/polygerrit-ui/app/elements/lit/subscription-controller.ts b/polygerrit-ui/app/elements/lit/subscription-controller.ts
new file mode 100644
index 0000000..ab4ed64
--- /dev/null
+++ b/polygerrit-ui/app/elements/lit/subscription-controller.ts
@@ -0,0 +1,48 @@
+/**
+ * @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 {ReactiveController, ReactiveControllerHost} from 'lit';
+import {Observable, Subscription} from 'rxjs';
+
+/**
+ * Enables components to simply hook up a property with an Observable like so:
+ *
+ * subscribe(this, obs$, x => (this.prop = x));
+ */
+export function subscribe<T>(
+ host: ReactiveControllerHost,
+ obs$: Observable<T>,
+ setProp: (t: T) => void
+) {
+ host.addController(new SubscriptionController(obs$, setProp));
+}
+
+export class SubscriptionController<T> implements ReactiveController {
+ private sub?: Subscription;
+
+ constructor(
+ private readonly obs$: Observable<T>,
+ private readonly setProp: (t: T) => void
+ ) {}
+
+ hostConnected() {
+ this.sub = this.obs$.subscribe(this.setProp);
+ }
+
+ hostDisconnected() {
+ this.sub?.unsubscribe();
+ }
+}
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
index 8138ff0..1be5e82 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator_test.js
@@ -51,7 +51,7 @@
let decorationHookWithSlot;
let replacementHook;
- setup(done => {
+ setup(async () => {
resetPlugins();
container = basicFixture.instantiate();
pluginApi.install(p => plugin = p, '0.1',
@@ -68,7 +68,7 @@
'second', 'other-module', {replace: true});
// Mimic all plugins loaded.
getPluginLoader().loadPlugins([]);
- flush(done);
+ await flush();
});
teardown(() => {
@@ -135,58 +135,52 @@
});
});
- test('late registration', done => {
+ test('late registration', async () => {
plugin.registerCustomComponent('banana', 'noob-noob');
- flush(() => {
- const element =
- container.querySelector('gr-endpoint-decorator[name="banana"]');
- const module = Array.from(element.root.children).find(
- element => element.nodeName === 'NOOB-NOOB');
- assert.isOk(module);
- done();
- });
+ await flush();
+ const element =
+ container.querySelector('gr-endpoint-decorator[name="banana"]');
+ const module = Array.from(element.root.children).find(
+ element => element.nodeName === 'NOOB-NOOB');
+ assert.isOk(module);
});
- test('two modules', done => {
+ test('two modules', async () => {
plugin.registerCustomComponent('banana', 'mod-one');
plugin.registerCustomComponent('banana', 'mod-two');
- flush(() => {
- const element =
- container.querySelector('gr-endpoint-decorator[name="banana"]');
- const module1 = Array.from(element.root.children).find(
- element => element.nodeName === 'MOD-ONE');
- assert.isOk(module1);
- const module2 = Array.from(element.root.children).find(
- element => element.nodeName === 'MOD-TWO');
- assert.isOk(module2);
- done();
- });
+ await flush();
+ const element =
+ container.querySelector('gr-endpoint-decorator[name="banana"]');
+ const module1 = Array.from(element.root.children).find(
+ element => element.nodeName === 'MOD-ONE');
+ assert.isOk(module1);
+ const module2 = Array.from(element.root.children).find(
+ element => element.nodeName === 'MOD-TWO');
+ assert.isOk(module2);
});
- test('late param setup', done => {
+ test('late param setup', async () => {
const element =
container.querySelector('gr-endpoint-decorator[name="banana"]');
const param = element.querySelector('gr-endpoint-param');
param['value'] = undefined;
plugin.registerCustomComponent('banana', 'noob-noob');
- flush(() => {
- let module = Array.from(element.root.children).find(
- element => element.nodeName === 'NOOB-NOOB');
- // Module waits for param to be defined.
- assert.isNotOk(module);
- const value = {abc: 'def'};
- param.value = value;
- flush(() => {
- module = Array.from(element.root.children).find(
- element => element.nodeName === 'NOOB-NOOB');
- assert.isOk(module);
- assert.strictEqual(module['someParam'], value);
- done();
- });
- });
+ await flush();
+ let module = Array.from(element.root.children).find(
+ element => element.nodeName === 'NOOB-NOOB');
+ // Module waits for param to be defined.
+ assert.isNotOk(module);
+ const value = {abc: 'def'};
+ param.value = value;
+
+ await flush();
+ module = Array.from(element.root.children).find(
+ element => element.nodeName === 'NOOB-NOOB');
+ assert.isOk(module);
+ assert.strictEqual(module['someParam'], value);
});
- test('param is bound', done => {
+ test('param is bound', async () => {
const element =
container.querySelector('gr-endpoint-decorator[name="banana"]');
const param = element.querySelector('gr-endpoint-param');
@@ -194,13 +188,11 @@
const value2 = {def: 'abc'};
param.value = value1;
plugin.registerCustomComponent('banana', 'noob-noob');
- flush(() => {
- const module = Array.from(element.root.children).find(
- element => element.nodeName === 'NOOB-NOOB');
- assert.strictEqual(module['someParam'], value1);
- param.value = value2;
- assert.strictEqual(module['someParam'], value2);
- done();
- });
+ await flush();
+ const module = Array.from(element.root.children).find(
+ element => element.nodeName === 'NOOB-NOOB');
+ assert.strictEqual(module['someParam'], value1);
+ param.value = value2;
+ assert.strictEqual(module['someParam'], value2);
});
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
index 6291e64..4e3d657 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper_test.js
@@ -19,6 +19,7 @@
import {addListener} from '@polymer/polymer/lib/utils/gestures.js';
import {Polymer} from '@polymer/polymer/lib/legacy/polymer-fn.js';
import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
+import {mockPromise} from '../../../test/test-utils.js';
Polymer({
is: 'gr-event-helper-some-element',
@@ -47,11 +48,13 @@
instance = plugin.eventHelper(element);
});
- test('onTap()', done => {
+ test('onTap()', async () => {
+ const promise = mockPromise();
instance.onTap(() => {
- done();
+ promise.resolve();
});
MockInteractions.tap(element);
+ await promise;
});
test('onTap() cancel', () => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
index e4d84e3..7fee4a0 100644
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-plugin-host/gr-plugin-host.ts
@@ -14,13 +14,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property, PropertyValues} from 'lit-element';
+import {LitElement, PropertyValues} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
import {ServerInfo} from '../../../types/common';
@customElement('gr-plugin-host')
-export class GrPluginHost extends GrLitElement {
+export class GrPluginHost extends LitElement {
@property({type: Object})
config?: ServerInfo;
@@ -37,7 +37,7 @@
getPluginLoader().loadPlugins(pluginsPending);
}
- updated(changedProperties: PropertyValues<GrPluginHost>) {
+ override updated(changedProperties: PropertyValues<GrPluginHost>) {
if (changedProperties.has('config') && this.config) {
this._configChanged(this.config);
}
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.ts b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.ts
index a186f70..342cf83 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-plugin-popup_test.ts
@@ -36,11 +36,9 @@
assert.isOk(element);
});
- test('open uses open() from gr-overlay', done => {
- element.open().then(() => {
- assert.isTrue(overlayOpen.called);
- done();
- });
+ test('open uses open() from gr-overlay', async () => {
+ await element.open();
+ assert.isTrue(overlayOpen.called);
});
test('close uses close() from gr-overlay', () => {
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 8ed6611..45a93bf 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
@@ -51,6 +51,11 @@
return dom(this.popup) as unknown as HTMLElement;
}
+ appendContent(el: HTMLElement) {
+ if (!this.popup) throw new Error('popup element not (yet) available');
+ this.popup.appendChild(el);
+ }
+
/**
* Opens the popup, inserts it into DOM over current UI.
* Creates the popup if not previously created. Creates popup content element,
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.js b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.js
index 8a7788f..2889333 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.js
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface_test.js
@@ -56,27 +56,23 @@
instance = new GrPopupInterface(plugin);
});
- test('open', done => {
- instance.open().then(api => {
- assert.strictEqual(api, instance);
- const manual = document.createElement('div');
- manual.id = 'foobar';
- manual.innerHTML = 'manual content';
- api._getElement().appendChild(manual);
- flush();
- assert.equal(
- container.querySelector('#foobar').textContent, 'manual content');
- done();
- });
+ test('open', async () => {
+ const api = await instance.open();
+ assert.strictEqual(api, instance);
+ const manual = document.createElement('div');
+ manual.id = 'foobar';
+ manual.innerHTML = 'manual content';
+ api._getElement().appendChild(manual);
+ await flush();
+ assert.equal(
+ container.querySelector('#foobar').textContent, 'manual content');
});
- test('close', done => {
- instance.open().then(api => {
- assert.isTrue(api._getElement().node.opened);
- api.close();
- assert.isFalse(api._getElement().node.opened);
- done();
- });
+ test('close', async () => {
+ const api = await instance.open();
+ assert.isTrue(api._getElement().node.opened);
+ api.close();
+ assert.isFalse(api._getElement().node.opened);
});
});
@@ -85,21 +81,16 @@
instance = new GrPopupInterface(plugin, 'gr-user-test-popup');
});
- test('open', done => {
- instance.open().then(api => {
- assert.isNotNull(
- container.querySelector('gr-user-test-popup'));
- done();
- });
+ test('open', async () => {
+ await instance.open();
+ assert.isNotNull(container.querySelector('gr-user-test-popup'));
});
- test('close', done => {
- instance.open().then(api => {
- assert.isTrue(api._getElement().node.opened);
- api.close();
- assert.isFalse(api._getElement().node.opened);
- done();
- });
+ test('close', async () => {
+ const api = await instance.open();
+ assert.isTrue(api._getElement().node.opened);
+ api.close();
+ assert.isFalse(api._getElement().node.opened);
});
});
});
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.ts b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.ts
index f913cf6..6580ad6 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-custom-plugin-header.ts
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+/* eslint-disable lit/no-legacy-template-syntax,lit/prefer-static-styles */
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {html} from '@polymer/polymer/lib/utils/html-tag';
import {customElement, property} from '@polymer/decorators';
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
index 514f00e..51259c8 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
@@ -56,7 +56,7 @@
<span class="title">Registered</span>
<span class="value">
<gr-date-formatter
- has-tooltip=""
+ withTooltip
date-str="[[_account.registered_on]]"
></gr-date-formatter>
</span>
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
index 4a4862b..f1813a4 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.ts
@@ -27,7 +27,7 @@
createServerInfo,
} from '../../../test/test-data-generators';
import {IronInputElement} from '@polymer/iron-input';
-import {SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonStubbedMember} from 'sinon';
import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
const basicFixture = fixtureFromElement('gr-account-info');
@@ -157,7 +157,7 @@
statusStub = stubRestApi('setAccountStatus').returns(Promise.resolve());
});
- test('name', done => {
+ test('name', async () => {
assert.isTrue(element.nameMutable);
assert.isFalse(element.hasUnsavedChanges);
@@ -167,18 +167,15 @@
assert.isFalse(statusChangedSpy.called);
assert.isTrue(element.hasUnsavedChanges);
- element.save().then(() => {
- assert.isFalse(usernameStub.called);
- assert.isTrue(nameStub.called);
- assert.isFalse(statusStub.called);
- nameStub.lastCall.returnValue.then(() => {
- assert.equal(nameStub.lastCall.args[0], 'new name');
- done();
- });
- });
+ await element.save();
+ assert.isFalse(usernameStub.called);
+ assert.isTrue(nameStub.called);
+ assert.isFalse(statusStub.called);
+ await nameStub.lastCall.returnValue;
+ assert.equal(nameStub.lastCall.args[0], 'new name');
});
- test('username', done => {
+ test('username', async () => {
element.set('_account.username', '');
element._hasUsernameChange = false;
assert.isTrue(element.usernameMutable);
@@ -189,18 +186,15 @@
assert.isFalse(statusChangedSpy.called);
assert.isTrue(element.hasUnsavedChanges);
- element.save().then(() => {
- assert.isTrue(usernameStub.called);
- assert.isFalse(nameStub.called);
- assert.isFalse(statusStub.called);
- usernameStub.lastCall.returnValue.then(() => {
- assert.equal(usernameStub.lastCall.args[0], 'new username');
- done();
- });
- });
+ await element.save();
+ assert.isTrue(usernameStub.called);
+ assert.isFalse(nameStub.called);
+ assert.isFalse(statusStub.called);
+ await usernameStub.lastCall.returnValue;
+ assert.equal(usernameStub.lastCall.args[0], 'new username');
});
- test('status', done => {
+ test('status', async () => {
assert.isFalse(element.hasUnsavedChanges);
element.set('_account.status', 'new status');
@@ -209,15 +203,12 @@
assert.isTrue(statusChangedSpy.called);
assert.isTrue(element.hasUnsavedChanges);
- element.save().then(() => {
- assert.isFalse(usernameStub.called);
- assert.isTrue(statusStub.called);
- assert.isFalse(nameStub.called);
- statusStub.lastCall.returnValue.then(() => {
- assert.equal(statusStub.lastCall.args[0], 'new status');
- done();
- });
- });
+ await element.save();
+ assert.isFalse(usernameStub.called);
+ assert.isTrue(statusStub.called);
+ assert.isFalse(nameStub.called);
+ await statusStub.lastCall.returnValue;
+ assert.equal(statusStub.lastCall.args[0], 'new status');
});
});
@@ -239,7 +230,7 @@
stubRestApi('setAccountUsername').returns(Promise.resolve());
});
- test('set name and status', done => {
+ test('set name and status', async () => {
assert.isTrue(element.nameMutable);
assert.isFalse(element.hasUnsavedChanges);
@@ -253,16 +244,13 @@
assert.isTrue(element.hasUnsavedChanges);
- element.save().then(() => {
- assert.isTrue(statusStub.called);
- assert.isTrue(nameStub.called);
+ await element.save();
+ assert.isTrue(statusStub.called);
+ assert.isTrue(nameStub.called);
- assert.equal(nameStub.lastCall.args[0], 'new name');
+ assert.equal(nameStub.lastCall.args[0], 'new name');
- assert.equal(statusStub.lastCall.args[0], 'new status');
-
- done();
- });
+ assert.equal(statusStub.lastCall.args[0], 'new status');
});
});
@@ -277,7 +265,7 @@
statusStub = stubRestApi('setAccountStatus').returns(Promise.resolve());
});
- test('read full name but set status', done => {
+ test('read full name but set status', async () => {
const section = element.$.nameSection;
const displaySpan = section.querySelectorAll('.value')[0];
const inputSpan = section.querySelectorAll('.value')[1];
@@ -296,13 +284,10 @@
assert.isTrue(element.hasUnsavedChanges);
- element.save().then(() => {
- assert.isTrue(statusStub.called);
- statusStub.lastCall.returnValue.then(() => {
- assert.equal(statusStub.lastCall.args[0], 'new status');
- done();
- });
- });
+ await element.save();
+ assert.isTrue(statusStub.called);
+ await statusStub.lastCall.returnValue;
+ assert.equal(statusStub.lastCall.args[0], 'new status');
});
});
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
index 41fc71a..a972db3 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
@@ -20,7 +20,8 @@
import {appContext} from '../../../services/app-context';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {css, customElement, html, property, LitElement} from 'lit-element';
+import {css, html, LitElement} from 'lit';
+import {customElement, property} from 'lit/decorators';
@customElement('gr-agreements-list')
export class GrAgreementsList extends LitElement {
@@ -40,7 +41,7 @@
});
}
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -70,7 +71,7 @@
`;
}
- render() {
+ override render() {
return html` <div class="gr-form-styles">
<table id="agreements">
<thead>
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
index 6c942b0..96b1ded 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
@@ -15,19 +15,18 @@
* limitations under the License.
*/
import '../../shared/gr-button/gr-button';
-import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../../styles/shared-styles';
import '../../../styles/gr-form-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-change-table-editor_html';
-import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
import {customElement, property, observe} from '@polymer/decorators';
import {ServerInfo} from '../../../types/common';
import {appContext} from '../../../services/app-context';
+import {columnNames} from '../../change-list/gr-change-list/gr-change-list';
@customElement('gr-change-table-editor')
-export class GrChangeTableEditor extends ChangeTableMixin(PolymerElement) {
+export class GrChangeTableEditor extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -48,18 +47,33 @@
@observe('serverConfig')
_configChanged(config: ServerInfo) {
- this.defaultColumns = this.getEnabledColumns(
- this.columnNames,
- config,
- this.flagsService.enabledExperiments
+ this.defaultColumns = columnNames.filter(col =>
+ this._isColumnEnabled(col, config, this.flagsService.enabledExperiments)
);
if (!this.displayedColumns) return;
this.displayedColumns = this.displayedColumns.filter(column =>
- this.isColumnEnabled(column, config, this.flagsService.enabledExperiments)
+ this._isColumnEnabled(
+ column,
+ config,
+ this.flagsService.enabledExperiments
+ )
);
}
/**
+ * Is the column disabled by a server config or experiment? For example the
+ * assignee feature might be disabled and thus the corresponding column is
+ * also disabled.
+ *
+ */
+ _isColumnEnabled(column: string, config: ServerInfo, experiments: string[]) {
+ if (!config || !config.change) return true;
+ if (column === 'Assignee') return !!config.change.enable_assignee;
+ if (column === 'Comments') return experiments.includes('comments-column');
+ return true;
+ }
+
+ /**
* Get the list of enabled column names from whichever checkboxes are
* checked (excluding the number checkbox).
*/
@@ -76,6 +90,13 @@
.map(checkbox => checkbox.name);
}
+ _computeIsColumnHidden(columnToCheck?: string, columnsToDisplay?: string[]) {
+ if (!columnsToDisplay || !columnToCheck) {
+ return false;
+ }
+ return !columnsToDisplay.includes(columnToCheck);
+ }
+
/**
* Handle a click on a checkbox container and relay the click to the checkbox it
* contains.
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_html.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_html.ts
index a05ec73..e756a20 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_html.ts
@@ -74,7 +74,7 @@
type="checkbox"
name="[[item]]"
on-click="_handleTargetClick"
- checked$="[[!isColumnHidden(item, displayedColumns)]]"
+ checked$="[[!_computeIsColumnHidden(item, displayedColumns)]]"
/>
</td>
</tr>
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts
index 4f61972..4f8d0a0 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor_test.ts
@@ -117,7 +117,7 @@
test('_getDisplayedColumns', () => {
const enabledColumns = columns.filter(column =>
- element.isColumnEnabled(column, element.serverConfig!, [])
+ element._isColumnEnabled(column, element.serverConfig!, [])
);
assert.deepEqual(element._getDisplayedColumns(), enabledColumns);
const input = queryAndAssert<HTMLInputElement>(
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
index 76047f4..5b757e6 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/shared-styles';
import '../../shared/gr-button/gr-button';
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
index 4800e5b..ce95ccb 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
h1 {
margin-bottom: var(--spacing-m);
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
index 8820748..ba736a2 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
@@ -17,7 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-gpg-editor.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {mockPromise, stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-gpg-editor');
@@ -25,7 +25,7 @@
let element;
let keys;
- setup(done => {
+ setup(async () => {
const fingerprint1 = '0192 723D 42D1 0C5B 32A6 E1E0 9350 9E4B AFC8 A49B';
const fingerprint2 = '0196 723D 42D1 0C5B 32A6 E1E0 9350 9E4B AFC8 A49B';
keys = {
@@ -55,7 +55,8 @@
element = basicFixture.instantiate();
- element.loadData().then(() => { flush(done); });
+ await element.loadData();
+ await flush();
});
test('renders', () => {
@@ -70,7 +71,7 @@
assert.equal(cells[0].textContent, 'AED9B59C');
});
- test('remove key', done => {
+ test('remove key', async () => {
const lastKey = keys[Object.keys(keys)[1]];
const saveStub = stubRestApi('deleteAccountGPGKey')
@@ -91,13 +92,11 @@
assert.isTrue(element.hasUnsavedChanges);
assert.isFalse(saveStub.called);
- element.save().then(() => {
- assert.isTrue(saveStub.called);
- assert.equal(saveStub.lastCall.args[0], Object.keys(keys)[1]);
- assert.equal(element._keysToRemove.length, 0);
- assert.isFalse(element.hasUnsavedChanges);
- done();
- });
+ await element.save();
+ assert.isTrue(saveStub.called);
+ assert.equal(saveStub.lastCall.args[0], Object.keys(keys)[1]);
+ assert.equal(element._keysToRemove.length, 0);
+ assert.isFalse(element.hasUnsavedChanges);
});
test('show key', () => {
@@ -113,7 +112,7 @@
assert.isTrue(openSpy.called);
});
- test('add key', done => {
+ test('add key', async () => {
const newKeyString =
'-----BEGIN PGP PUBLIC KEY BLOCK-----' +
'\nVersion: BCPG v1.52\n\t<key 3>';
@@ -138,11 +137,12 @@
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
+ const promise = mockPromise();
element._handleAddKey().then(() => {
assert.isTrue(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
assert.equal(element._keys.length, 2);
- done();
+ promise.resolve();
});
assert.isTrue(element.$.addButton.disabled);
@@ -150,9 +150,10 @@
assert.isTrue(addStub.called);
assert.deepEqual(addStub.lastCall.args[0], {add: [newKeyString]});
+ await promise;
});
- test('add invalid key', done => {
+ test('add invalid key', async () => {
const newKeyString = 'not even close to valid';
const addStub = stubRestApi(
@@ -164,11 +165,12 @@
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
+ const promise = mockPromise();
element._handleAddKey().then(() => {
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
assert.equal(element._keys.length, 2);
- done();
+ promise.resolve();
});
assert.isTrue(element.$.addButton.disabled);
@@ -176,6 +178,7 @@
assert.isTrue(addStub.called);
assert.deepEqual(addStub.lastCall.args[0], {add: [newKeyString]});
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
index 2757454..8f1706d 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
@@ -20,8 +20,8 @@
import {appContext} from '../../../services/app-context';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, state} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, state} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -29,7 +29,7 @@
}
}
@customElement('gr-group-list')
-export class GrGroupList extends GrLitElement {
+export class GrGroupList extends LitElement {
@state()
protected _groups: GroupInfo[] = [];
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.ts
index 3dce295..a1534af 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_test.ts
@@ -28,7 +28,7 @@
let element: GrGroupList;
let groups: GroupInfo[];
- setup(done => {
+ setup(async () => {
groups = [
{
url: 'some url',
@@ -58,9 +58,8 @@
element = basicFixture.instantiate();
- element.loadData().then(() => {
- flush(done);
- });
+ await element.loadData();
+ await flush();
});
test('renders', async () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
index ccf8a01..c62cff4 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
@@ -21,8 +21,8 @@
import {appContext} from '../../../services/app-context';
import {formStyles} from '../../../styles/gr-form-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, query} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property, query} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -31,7 +31,7 @@
}
@customElement('gr-http-password')
-export class GrHttpPassword extends GrLitElement {
+export class GrHttpPassword extends LitElement {
@query('#generatedPasswordOverlay')
generatedPasswordOverlay?: GrOverlay;
@@ -75,7 +75,7 @@
return Promise.all(promises);
}
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
formStyles,
@@ -113,7 +113,7 @@
];
}
- render() {
+ override render() {
return html` <div class="gr-form-styles">
<div ?hidden=${this._passwordUrl}>
<section>
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.ts
index 004f18f..eab8d2e 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.ts
@@ -35,7 +35,7 @@
let account: AccountDetailInfo;
let config: ServerInfo;
- setup(done => {
+ setup(async () => {
account = {...createAccountDetailWithId(), username: 'user name'};
config = createServerInfo();
@@ -43,9 +43,8 @@
stubRestApi('getConfig').returns(Promise.resolve(config));
element = basicFixture.instantiate();
- element.loadData().then(() => {
- flush(done);
- });
+ await element.loadData();
+ await flush();
});
test('generate password', () => {
@@ -76,12 +75,10 @@
assert.isNull(element._passwordUrl);
});
- test('with http_password_url', done => {
+ test('with http_password_url', async () => {
config.auth.http_password_url = 'http://example.com/';
- element.loadData().then(() => {
- assert.isNotNull(element._passwordUrl);
- assert.equal(element._passwordUrl, config.auth.http_password_url);
- done();
- });
+ await element.loadData();
+ assert.isNotNull(element._passwordUrl);
+ assert.equal(element._passwordUrl, config.auth.http_password_url);
});
});
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
index d1a4f8f..9d8dcc5 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_test.ts
@@ -88,13 +88,11 @@
assert.isTrue(element.filterIdentities(ids[1]));
});
- test('delete id', done => {
+ test('delete id', async () => {
element._idName = 'mailto:gerrit2@example.com';
const loadDataStub = sinon.stub(element, 'loadData');
- element._handleDeleteItemConfirm().then(() => {
- assert.isTrue(loadDataStub.called);
- done();
- });
+ await element._handleDeleteItemConfirm();
+ assert.isTrue(loadDataStub.called);
});
test('_handleDeleteItem opens modal', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index ace1e1a..4096b02 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -16,7 +16,6 @@
*/
import '@polymer/iron-input/iron-input';
import '../../shared/gr-button/gr-button';
-import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../../styles/shared-styles';
import '../../../styles/gr-form-styles';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.js b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.js
index 19852d9..1ca4852 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor_test.js
@@ -46,7 +46,7 @@
MockInteractions.tap(button);
}
- setup(done => {
+ setup(async () => {
element = basicFixture.instantiate();
menu = [
{url: '/first/url', name: 'first name', target: '_blank'},
@@ -55,7 +55,7 @@
];
element.set('menuItems', menu);
flush$0();
- flush(done);
+ await flush();
});
test('renders', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
index 6c21e58..07a2e51 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_test.ts
@@ -93,38 +93,34 @@
return promise;
}
- test('fires the close event on close', done => {
- close().then(done);
+ test('fires the close event on close', async () => {
+ await close();
});
- test('fires the close event on save', done => {
- close(() =>
+ test('fires the close event on save', async () => {
+ await close(() =>
MockInteractions.tap(queryAndAssert(element, '#saveButton'))
- ).then(done);
+ );
});
- test('saves account details', done => {
- flush(() => {
- element.$.name.value = 'new name';
+ test('saves account details', async () => {
+ await flush();
+ element.$.name.value = 'new name';
- element.set('_account.username', '');
- element._hasUsernameChange = false;
- assert.isTrue(element._usernameMutable);
+ element.set('_account.username', '');
+ element._hasUsernameChange = false;
+ assert.isTrue(element._usernameMutable);
- element.set('_username', 'new username');
+ element.set('_username', 'new username');
- // Nothing should be committed yet.
- assert.equal(account.name, 'name');
- assert.isNotOk(account.username);
+ // Nothing should be committed yet.
+ assert.equal(account.name, 'name');
+ assert.isNotOk(account.username);
- // Save and verify new values are committed.
- save()
- .then(() => {
- assert.equal(account.name, 'new name');
- assert.equal(account.username, 'new username');
- })
- .then(done);
- });
+ // Save and verify new values are committed.
+ await save();
+ assert.equal(account.name, 'new name');
+ assert.equal(account.username, 'new username');
});
test('save btn disabled', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
index ecb02eb..64409d5 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-item.ts
@@ -14,9 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
+import {formStyles} from '../../../styles/gr-form-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -25,7 +25,7 @@
}
@customElement('gr-settings-item')
-export class GrSettingsItem extends GrLitElement {
+export class GrSettingsItem extends LitElement {
@property({type: String})
anchor?: string;
@@ -34,6 +34,7 @@
static override get styles() {
return [
+ formStyles,
css`
:host {
display: block;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
index 0748379..9e4ea0a 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-menu-item.ts
@@ -16,8 +16,8 @@
*/
import {pageNavStyles} from '../../../styles/gr-page-nav-styles';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, html, property} from 'lit-element';
+import {LitElement, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -26,7 +26,7 @@
}
@customElement('gr-settings-menu-item')
-export class GrSettingsMenuItem extends GrLitElement {
+export class GrSettingsMenuItem extends LitElement {
@property({type: String})
href?: string;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 91b2ed6..94333c7 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -16,6 +16,7 @@
*/
import '@polymer/iron-input/iron-input';
import '@polymer/paper-toggle-button/paper-toggle-button';
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-form-styles';
import '../../../styles/gr-menu-page-styles';
import '../../../styles/gr-page-nav-styles';
@@ -28,7 +29,6 @@
import '../gr-change-table-editor/gr-change-table-editor';
import '../../shared/gr-button/gr-button';
import {GrButton} from '../../shared/gr-button/gr-button';
-import '../../shared/gr-date-formatter/gr-date-formatter';
import '../../shared/gr-diff-preferences/gr-diff-preferences';
import '../../shared/gr-page-nav/gr-page-nav';
import '../../shared/gr-select/gr-select';
@@ -46,7 +46,6 @@
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-settings-view_html';
import {getDocsBaseUrl} from '../../../utils/url-util';
-import {ChangeTableMixin} from '../../../mixins/gr-change-table-mixin/gr-change-table-mixin';
import {customElement, property, observe} from '@polymer/decorators';
import {AppElementParams} from '../../gr-app-types';
import {GrAccountInfo} from '../gr-account-info/gr-account-info';
@@ -75,6 +74,7 @@
EmailStrategy,
TimeFormat,
} from '../../../constants/constants';
+import {columnNames} from '../../change-list/gr-change-list/gr-change-list';
const PREFS_SECTION_FIELDS: Array<keyof PreferencesInput> = [
'changes_per_page',
@@ -84,6 +84,7 @@
'diff_view',
'publish_comments_on_push',
'disable_keyboard_shortcuts',
+ 'disable_token_highlighting',
'work_in_progress_by_default',
'default_base_for_merges',
'signed_off_by',
@@ -123,6 +124,7 @@
showSizeBarsInFileList: HTMLInputElement;
publishCommentsOnPush: HTMLInputElement;
disableKeyboardShortcuts: HTMLInputElement;
+ disableTokenHighlighting: HTMLInputElement;
relativeDateInChangeTable: HTMLInputElement;
changesPerPageSelect: HTMLInputElement;
dateTimeFormatSelect: HTMLInputElement;
@@ -137,7 +139,7 @@
}
@customElement('gr-settings-view')
-export class GrSettingsView extends ChangeTableMixin(PolymerElement) {
+export class GrSettingsView extends PolymerElement {
static get template() {
return htmlTemplate;
}
@@ -256,8 +258,10 @@
this._localMenu = this._cloneMenu(prefs.my);
this._localChangeTableColumns =
prefs.change_table.length === 0
- ? this.columnNames
- : this.renameProjectToRepoColumn(prefs.change_table);
+ ? columnNames
+ : prefs.change_table.map(column =>
+ column === 'Project' ? 'Repo' : column
+ );
})
);
@@ -404,6 +408,13 @@
);
}
+ _handleDisableTokenHighlightingChanged() {
+ this.set(
+ '_localPrefs.disable_token_highlighting',
+ this.$.disableTokenHighlighting.checked
+ );
+ }
+
_handleWorkInProgressByDefault() {
this.set(
'_localPrefs.work_in_progress_by_default',
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
index 167417d..78c4a62 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
color: var(--primary-text-color);
@@ -306,6 +309,19 @@
</span>
</section>
<section>
+ <label for="disableTokenHighlighting" class="title"
+ >Disable token highlighting on hover</label
+ >
+ <span class="value">
+ <input
+ id="disableTokenHighlighting"
+ type="checkbox"
+ checked$="[[_localPrefs.disable_token_highlighting]]"
+ on-change="_handleDisableTokenHighlightingChanged"
+ />
+ </span>
+ </section>
+ <section>
<label for="insertSignedOff" class="title">
Insert Signed-off-by Footer For Inline Edit Changes
</label>
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.ts
index 19aeccb..8194d5b 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.ts
@@ -93,7 +93,7 @@
);
}
- setup(done => {
+ setup(async () => {
account = {
...createAccountDetailWithId(123),
name: 'user name',
@@ -126,7 +126,8 @@
element = basicFixture.instantiate();
// Allow the element to render.
- element._testOnly_loadingPromise?.then(done);
+ if (element._testOnly_loadingPromise)
+ await element._testOnly_loadingPromise;
});
test('theme changing', () => {
@@ -164,7 +165,7 @@
assert.equal(titleChangedStub.getCall(0).args[0].detail.title, 'Settings');
});
- test('user preferences', done => {
+ test('user preferences', async () => {
// Rendered with the expected preferences selected.
assert.equal(
Number(
@@ -243,6 +244,13 @@
);
assert.equal(
(
+ valueOf('Disable token highlighting on hover', 'preferences')!
+ .firstElementChild as HTMLInputElement
+ ).checked,
+ false
+ );
+ assert.equal(
+ (
valueOf(
'Insert Signed-off-by Footer For Inline Edit Changes',
'preferences'
@@ -269,14 +277,12 @@
});
// Save the change.
- element._handleSavePreferences().then(() => {
- assert.isFalse(element._prefsChanged);
- assert.isFalse(element._menuChanged);
- done();
- });
+ await element._handleSavePreferences();
+ assert.isFalse(element._prefsChanged);
+ assert.isFalse(element._menuChanged);
});
- test('publish comments on push', done => {
+ test('publish comments on push', async () => {
const publishCommentsOnPush = valueOf(
'Publish comments on push',
'preferences'
@@ -292,14 +298,12 @@
});
// Save the change.
- element._handleSavePreferences().then(() => {
- assert.isFalse(element._prefsChanged);
- assert.isFalse(element._menuChanged);
- done();
- });
+ await element._handleSavePreferences();
+ assert.isFalse(element._prefsChanged);
+ assert.isFalse(element._menuChanged);
});
- test('set new changes work-in-progress', done => {
+ test('set new changes work-in-progress', async () => {
const newChangesWorkInProgress = valueOf(
'Set new changes to "work in progress" by default',
'preferences'
@@ -315,14 +319,12 @@
});
// Save the change.
- element._handleSavePreferences().then(() => {
- assert.isFalse(element._prefsChanged);
- assert.isFalse(element._menuChanged);
- done();
- });
+ await element._handleSavePreferences();
+ assert.isFalse(element._prefsChanged);
+ assert.isFalse(element._menuChanged);
});
- test('menu', done => {
+ test('menu', async () => {
assert.isFalse(element._menuChanged);
assert.isFalse(element._prefsChanged);
@@ -349,12 +351,10 @@
return Promise.resolve(new Response());
});
- element._handleSaveMenu().then(() => {
- assert.isFalse(element._menuChanged);
- assert.isFalse(element._prefsChanged);
- assertMenusEqual(element.prefs.my, element._localMenu);
- done();
- });
+ await element._handleSaveMenu();
+ assert.isFalse(element._menuChanged);
+ assert.isFalse(element._prefsChanged);
+ assertMenusEqual(element.prefs.my, element._localMenu);
});
test('add email validation', () => {
@@ -388,7 +388,7 @@
assert.isFalse(addEmailStub.called);
});
- test('add email does save valid', done => {
+ test('add email does save valid', async () => {
const addEmailStub = stubAddAccountEmail(201);
assert.isFalse(element._addingEmail);
@@ -401,13 +401,11 @@
assert.isTrue(addEmailStub.called);
assert.isTrue(addEmailStub.called);
- addEmailStub.lastCall.returnValue.then(() => {
- assert.isOk(element._lastSentVerificationEmail);
- done();
- });
+ await addEmailStub.lastCall.returnValue;
+ assert.isOk(element._lastSentVerificationEmail);
});
- test('add email does not set last-email if error', done => {
+ test('add email does not set last-email if error', async () => {
const addEmailStub = stubAddAccountEmail(500);
assert.isNotOk(element._lastSentVerificationEmail);
@@ -416,10 +414,8 @@
element._handleAddEmailButton();
assert.isTrue(addEmailStub.called);
- addEmailStub.lastCall.returnValue.then(() => {
- assert.isNotOk(element._lastSentVerificationEmail);
- done();
- });
+ await addEmailStub.lastCall.returnValue;
+ assert.isNotOk(element._lastSentVerificationEmail);
});
test('emails are loaded without emailToken', () => {
@@ -450,7 +446,7 @@
assert.isTrue(element.prefs.legacycid_in_change_table);
});
- test('reset menu item back to default', done => {
+ test('reset menu item back to default', async () => {
const originalMenu = {
...createDefaultPreferences(),
my: [
@@ -471,10 +467,8 @@
element.set('_localMenu', updatedMenu);
- element._handleResetMenuButton().then(() => {
- assertMenusEqual(element._localMenu, originalMenu.my);
- done();
- });
+ await element._handleResetMenuButton();
+ assertMenusEqual(element._localMenu, originalMenu.my);
});
test('test that reset button is called', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
index 8f99baa..cd2c1df 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
@@ -17,7 +17,7 @@
import '../../../test/common-test-setup-karma.js';
import './gr-ssh-editor.js';
-import {stubRestApi} from '../../../test/test-utils.js';
+import {mockPromise, stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromElement('gr-ssh-editor');
@@ -25,7 +25,7 @@
let element;
let keys;
- setup(done => {
+ setup(async () => {
keys = [{
seq: 1,
ssh_public_key: 'ssh-rsa <key 1> comment-one@machine-one',
@@ -46,7 +46,8 @@
element = basicFixture.instantiate();
- element.loadData().then(() => { flush(done); });
+ await element.loadData();
+ await flush();
});
test('renders', () => {
@@ -61,7 +62,7 @@
assert.equal(cells[0].textContent, keys[1].comment);
});
- test('remove key', done => {
+ test('remove key', async () => {
const lastKey = keys[1];
const saveStub = stubRestApi('deleteAccountSSHKey')
@@ -82,13 +83,11 @@
assert.isTrue(element.hasUnsavedChanges);
assert.isFalse(saveStub.called);
- element.save().then(() => {
- assert.isTrue(saveStub.called);
- assert.equal(saveStub.lastCall.args[0], lastKey.seq);
- assert.equal(element._keysToRemove.length, 0);
- assert.isFalse(element.hasUnsavedChanges);
- done();
- });
+ await element.save();
+ assert.isTrue(saveStub.called);
+ assert.equal(saveStub.lastCall.args[0], lastKey.seq);
+ assert.equal(element._keysToRemove.length, 0);
+ assert.isFalse(element.hasUnsavedChanges);
});
test('show key', () => {
@@ -104,7 +103,7 @@
assert.isTrue(openSpy.called);
});
- test('add key', done => {
+ test('add key', async () => {
const newKeyString = 'ssh-rsa <key 3> comment-three@machine-three';
const newKeyObject = {
seq: 3,
@@ -124,11 +123,12 @@
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
+ const promise = mockPromise();
element._handleAddKey().then(() => {
assert.isTrue(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
assert.equal(element._keys.length, 3);
- done();
+ promise.resolve();
});
assert.isTrue(element.$.addButton.disabled);
@@ -136,9 +136,10 @@
assert.isTrue(addStub.called);
assert.equal(addStub.lastCall.args[0], newKeyString);
+ await promise;
});
- test('add invalid key', done => {
+ test('add invalid key', async () => {
const newKeyString = 'not even close to valid';
const addStub = stubRestApi(
@@ -150,11 +151,12 @@
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
+ const promise = mockPromise();
element._handleAddKey().then(() => {
assert.isFalse(element.$.addButton.disabled);
assert.isFalse(element.$.newKey.disabled);
assert.equal(element._keys.length, 2);
- done();
+ promise.resolve();
});
assert.isTrue(element.$.addButton.disabled);
@@ -162,6 +164,7 @@
assert.isTrue(addStub.called);
assert.equal(addStub.lastCall.args[0], newKeyString);
+ await promise;
});
});
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.ts b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.ts
index cb4b86d..c0580f6 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_test.ts
@@ -28,7 +28,7 @@
suite('gr-watched-projects-editor tests', () => {
let element: GrWatchedProjectsEditor;
- setup(done => {
+ setup(async () => {
const projects = [
{
project: 'project a',
@@ -69,9 +69,8 @@
element = basicFixture.instantiate();
- element.loadData().then(() => {
- flush(done);
- });
+ await element.loadData();
+ await flush();
});
test('renders', () => {
@@ -102,27 +101,21 @@
assert.equal(checkedKeys[2], 'notify_all_comments');
});
- test('_getProjectSuggestions empty', done => {
- element._getProjectSuggestions('nonexistent').then(projects => {
- assert.equal(projects.length, 0);
- done();
- });
+ test('_getProjectSuggestions empty', async () => {
+ const projects = await element._getProjectSuggestions('nonexistent');
+ assert.equal(projects.length, 0);
});
- test('_getProjectSuggestions non-empty', done => {
- element._getProjectSuggestions('the project').then(projects => {
- assert.equal(projects.length, 1);
- assert.equal(projects[0].name, 'the project');
- done();
- });
+ test('_getProjectSuggestions non-empty', async () => {
+ const projects = await element._getProjectSuggestions('the project');
+ assert.equal(projects.length, 1);
+ assert.equal(projects[0].name, 'the project');
});
- test('_getProjectSuggestions non-empty with two letter project', done => {
- element._getProjectSuggestions('th').then(projects => {
- assert.equal(projects.length, 1);
- assert.equal(projects[0].name, 'the project');
- done();
- });
+ test('_getProjectSuggestions non-empty with two letter project', async () => {
+ const projects = await element._getProjectSuggestions('th');
+ assert.equal(projects.length, 1);
+ assert.equal(projects[0].name, 'the project');
});
test('_canAddProject', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index a3650b1..31c62b1 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -19,12 +19,12 @@
import '../gr-icons/gr-icons';
import {AccountInfo, ChangeInfo} from '../../../types/common';
import {appContext} from '../../../services/app-context';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
-import {classMap} from 'lit-html/directives/class-map';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
+import {classMap} from 'lit/directives/class-map';
@customElement('gr-account-chip')
-export class GrAccountChip extends GrLitElement {
+export class GrAccountChip extends LitElement {
/**
* Fired to indicate a key was pressed while this chip was focused.
*
@@ -128,6 +128,7 @@
override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
.container {
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index dc36c78..9897a9f 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -26,13 +26,14 @@
import {fireEvent} from '../../../utils/event-util';
import {isInvolved} from '../../../utils/change-util';
import {ShowAlertEventDetail} from '../../../types/events';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, state} from 'lit-element';
-import {classMap} from 'lit-html/directives/class-map';
+import {LitElement, css, html} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
+import {classMap} from 'lit/directives/class-map';
import {modifierPressed} from '../../../utils/dom-util';
+import {getRemovedByIconClickReason} from '../../../utils/attention-set-util';
@customElement('gr-account-label')
-export class GrAccountLabel extends GrLitElement {
+export class GrAccountLabel extends LitElement {
@property({type: Object})
account?: AccountInfo;
@@ -205,18 +206,7 @@
></gr-hovercard-account>`
: ''}
${hasAttention
- ? html`<gr-button
- id="attentionButton"
- link=""
- aria-label="Remove user from attention set"
- @click=${this._handleRemoveAttentionClick}
- ?disabled=${!this._computeAttentionButtonEnabled(
- highlightAttention,
- account,
- change,
- this.selected,
- this._selfAccount
- )}
+ ? html` <gr-tooltip-content
?has-tooltip=${this._computeAttentionButtonEnabled(
highlightAttention,
account,
@@ -232,11 +222,25 @@
this.selected,
this._selfAccount
)}"
- ><iron-icon
- class="attention"
- icon="gr-icons:attention"
- ></iron-icon>
- </gr-button>`
+ >
+ <gr-button
+ id="attentionButton"
+ link=""
+ aria-label="Remove user from attention set"
+ @click=${this._handleRemoveAttentionClick}
+ ?disabled=${!this._computeAttentionButtonEnabled(
+ highlightAttention,
+ account,
+ change,
+ this.selected,
+ this._selfAccount
+ )}
+ ><iron-icon
+ class="attention"
+ icon="gr-icons:attention"
+ ></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>`
: ''}
</span>
<span
@@ -338,8 +342,7 @@
// We are deliberately updating the UI before making the API call. It is a
// risk that we are taking to achieve a better UX for 99.9% of the cases.
- const selfName = getDisplayName(this._config, this._selfAccount);
- const reason = `Removed by ${selfName} by clicking the attention icon`;
+ const reason = getRemovedByIconClickReason(this._selfAccount, this._config);
if (this.change.attention_set)
delete this.change.attention_set[this.account._account_id];
// For re-evaluation of everything that depends on 'change'.
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
index 97b3b34..fbf29c63 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.ts
@@ -18,11 +18,11 @@
import '../gr-account-label/gr-account-label';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {AccountInfo, ChangeInfo} from '../../../types/common';
-import {css, customElement, html, property} from 'lit-element';
-import {GrLitElement} from '../../lit/gr-lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
@customElement('gr-account-link')
-export class GrAccountLink extends GrLitElement {
+export class GrAccountLink extends LitElement {
@property({type: String})
voteableText?: string;
@@ -95,7 +95,7 @@
?hideStatus=${this.hideStatus}
?firstName=${this.firstName}
.voteableText=${this.voteableText}
- part="gr-account-link-text => gr-account-label-text"
+ exportparts="gr-account-label-text: gr-account-link-text"
>
</gr-account-label>
</a>
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
index 220f5fd..ae3853e 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.ts
@@ -18,8 +18,8 @@
import '../../../styles/shared-styles';
import {getRootElement} from '../../../scripts/rootElement';
import {ErrorType} from '../../../types/types';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {customElement, property, css, html} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {sharedStyles} from '../../../styles/shared-styles';
declare global {
@@ -29,8 +29,8 @@
}
@customElement('gr-alert')
-export class GrAlert extends GrLitElement {
- static get styles() {
+export class GrAlert extends LitElement {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -93,9 +93,10 @@
>`;
}
- render() {
+ override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const style = html`<style>
.action {
--gr-button: {
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
index ac6c99e..a629d0e 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.ts
@@ -52,11 +52,14 @@
selected: HTMLElement | null;
}
-@customElement('gr-autocomplete-dropdown')
-export class GrAutocompleteDropdown extends IronFitMixin(
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = IronFitMixin(
KeyboardShortcutMixin(PolymerElement),
IronFitBehavior as IronFitBehavior
-) {
+);
+
+@customElement('gr-autocomplete-dropdown')
+export class GrAutocompleteDropdown extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index 7595a17..9918f39 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -29,6 +29,7 @@
import {CustomKeyboardEvent} from '../../../types/events';
import {fireEvent} from '../../../utils/event-util';
import {debounce, DelayedTask} from '../../../utils/async-util';
+import {PropertyType} from '../../../types/common';
const TOKENIZE_REGEX = /(?:[^\s"]+|"[^"]*")+/g;
const DEBOUNCE_WAIT_MS = 200;
@@ -40,9 +41,9 @@
};
}
-export type AutocompleteQuery = (
+export type AutocompleteQuery<T = string> = (
text: string
-) => Promise<AutocompleteSuggestion[]>;
+) => Promise<Array<AutocompleteSuggestion<T>>>;
declare global {
interface HTMLElementTagNameMap {
@@ -50,11 +51,11 @@
}
}
-export interface AutocompleteSuggestion {
+export interface AutocompleteSuggestion<T = string> {
name?: string;
label?: string;
- value?: string;
- text?: string;
+ value?: T;
+ text?: T;
}
export interface AutocompleteCommitEventDetail {
@@ -64,8 +65,11 @@
export type AutocompleteCommitEvent =
CustomEvent<AutocompleteCommitEventDetail>;
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-autocomplete')
-export class GrAutocomplete extends KeyboardShortcutMixin(PolymerElement) {
+export class GrAutocomplete extends base {
static get template() {
return htmlTemplate;
}
@@ -99,7 +103,7 @@
*
*/
@property({type: Object})
- query: AutocompleteQuery = () => Promise.resolve([]);
+ query?: AutocompleteQuery = () => Promise.resolve([]);
/**
* The number of characters that must be typed before suggestions are
@@ -295,6 +299,12 @@
if (this._disableSuggestions) {
return;
}
+
+ const query = this.query;
+ if (!query) {
+ return;
+ }
+
if (text.length < threshold) {
this.value = '';
return;
@@ -305,7 +315,7 @@
}
const update = () => {
- this.query(text).then(suggestions => {
+ query(text).then(suggestions => {
if (text !== this.text) {
// Late response.
return;
@@ -502,3 +512,24 @@
return showSearchIcon ? 'showSearchIcon' : '';
}
}
+
+/**
+ * Often gr-autocomplete is used for BranchName, RepoName, etc...
+ * GrTypedAutocomplete allows to define more precise typing in templates.
+ * For example, instead of
+ * $: {
+ * branchSelect: GrAutocomplete
+ * }
+ * you can write
+ * $: {
+ * branchSelect: GrTypedAutocomplete<BranchName>
+ * }
+ * And later user $.branchSelect.text without type conversion to BranchName.
+ */
+export interface GrTypedAutocomplete<
+ T extends PropertyType<GrAutocomplete, 'text'>
+> extends GrAutocomplete {
+ text: T;
+ value: T;
+ query?: AutocompleteQuery<T>;
+}
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index 6dd3a00..33bf6c6 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -18,11 +18,11 @@
import {getPluginLoader} from '../gr-js-api-interface/gr-plugin-loader';
import {AccountInfo} from '../../../types/common';
import {appContext} from '../../../services/app-context';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
@customElement('gr-avatar')
-export class GrAvatar extends GrLitElement {
+export class GrAvatar extends LitElement {
@property({type: Object})
account?: AccountInfo;
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.ts
index bb70855..b3c485a 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.ts
@@ -24,6 +24,7 @@
import {
createAccountWithEmail,
createAccountWithId,
+ createServerInfo,
} from '../../../test/test-data-generators';
const basicFixture = fixtureFromElement('gr-avatar');
@@ -116,9 +117,11 @@
suite('config set', () => {
setup(() => {
- stub('gr-avatar', '_getConfig').callsFake(() =>
- Promise.resolve({plugin: {has_avatars: true}})
- );
+ const config = {
+ ...createServerInfo(),
+ plugin: {has_avatars: true, js_resource_paths: []},
+ };
+ stub('gr-avatar', '_getConfig').returns(Promise.resolve(config));
element = basicFixture.instantiate();
});
@@ -154,9 +157,11 @@
let element: GrAvatar;
setup(() => {
- stub('gr-avatar', '_getConfig').callsFake(() =>
- Promise.resolve({plugin: {has_avatars: true}})
- );
+ const config = {
+ ...createServerInfo(),
+ plugin: {has_avatars: true, js_resource_paths: []},
+ };
+ stub('gr-avatar', '_getConfig').returns(Promise.resolve(config));
element = basicFixture.instantiate();
});
@@ -182,7 +187,7 @@
let element: GrAvatar;
setup(() => {
- stub('gr-avatar', '_getConfig').callsFake(() => Promise.resolve({}));
+ stub('gr-avatar', '_getConfig').returns(Promise.resolve(undefined));
element = basicFixture.instantiate();
});
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
index aef55fa..4467ba6 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.ts
@@ -15,13 +15,11 @@
* limitations under the License.
*/
import '@polymer/paper-button/paper-button';
-import '../../../styles/shared-styles';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {customElement, property, computed, observe} from '@polymer/decorators';
-import {htmlTemplate} from './gr-button_html';
-import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
+import {spinnerStyles} from '../../../styles/gr-spinner-styles';
+import {votingStyles} from '../../../styles/gr-voting-styles';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {
- PolymerEvent,
getEventPath,
getKeyboardEvent,
isModifierPressed,
@@ -37,72 +35,242 @@
}
@customElement('gr-button')
-export class GrButton extends TooltipMixin(PolymerElement) {
- static get template() {
- return htmlTemplate;
- }
+export class GrButton extends LitElement {
+ private readonly reporting: ReportingService = appContext.reportingService;
- @property({type: Boolean, reflectToAttribute: true})
- downArrow = false;
-
- @property({type: Boolean, reflectToAttribute: true})
- link = false;
-
- @property({type: Boolean})
- noUppercase = false;
-
- @property({type: Boolean, reflectToAttribute: true})
- loading = false;
-
- @property({type: Boolean, reflectToAttribute: true})
- disabled: boolean | null = null;
-
- @property({type: String})
- tooltip = '';
+ /**
+ * Should this button be rendered as a vote chip? Then we are applying
+ * the .voteChip class (see gr-voting-styles) to the paper-button.
+ */
+ @property({type: Boolean, reflect: true})
+ voteChip = false;
// Note: don't assign a value to this, since constructor is called
// after created, the initial value maybe overridden by this
- @property({type: String})
- _initialTabindex?: string;
+ private initialTabindex?: string;
- @computed('disabled', 'loading')
- get _disabled() {
- return this.disabled || this.loading;
+ @property({type: Boolean, reflect: true, attribute: 'down-arrow'})
+ downArrow = false;
+
+ @property({type: Boolean, reflect: true})
+ link = false;
+
+ @property({type: Boolean, reflect: true})
+ loading = false;
+
+ @property({type: Boolean, reflect: true})
+ disabled: boolean | null = null;
+
+ static override get styles() {
+ return [
+ votingStyles,
+ spinnerStyles,
+ css`
+ /* general styles for all buttons */
+ :host {
+ --background-color: var(
+ --button-background-color,
+ var(--default-button-background-color)
+ );
+ --text-color: var(--default-button-text-color);
+ display: inline-block;
+ position: relative;
+ }
+ :host([hidden]) {
+ display: none;
+ }
+ :host([no-uppercase]) paper-button {
+ text-transform: none;
+ }
+ paper-button {
+ /* The next lines contains a copy of paper-button style.
+ Without a copy, the @apply works incorrectly with Polymer 2.
+ @apply is deprecated and is not recommended to use. It is expected
+ that @apply will be replaced with the ::part CSS pseudo-element.
+ After replacement copied lines can be removed.
+ */
+ @apply --layout-inline;
+ @apply --layout-center-center;
+ position: relative;
+ box-sizing: border-box;
+ min-width: 5.14em;
+ margin: 0 0.29em;
+ background: transparent;
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
+ -webkit-tap-highlight-color: transparent;
+ font: inherit;
+ text-transform: uppercase;
+ outline-width: 0;
+ border-top-left-radius: var(--border-radius);
+ border-top-right-radius: var(--border-radius);
+ border-bottom-right-radius: var(--border-radius);
+ border-bottom-left-radius: var(--border-radius);
+ -moz-user-select: none;
+ -ms-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ z-index: 0;
+ padding: var(--spacing-m);
+
+ @apply --paper-font-common-base;
+ @apply --paper-button;
+ /* End of copy*/
+
+ /* paper-button sets this to anti-aliased, which appears different than
+ bold font elsewhere on macOS. */
+ -webkit-font-smoothing: initial;
+ align-items: center;
+ background-color: var(--background-color);
+ color: var(--text-color);
+ display: flex;
+ font-family: inherit;
+ justify-content: center;
+ margin: var(--margin, 0);
+ min-width: var(--border, 0);
+ padding: var(--padding, 4px 8px);
+ @apply --gr-button;
+ }
+ /* https://github.com/PolymerElements/paper-button/blob/2.x/paper-button.html */
+ /* BEGIN: Copy from paper-button */
+ paper-button[elevation='1'] {
+ @apply --paper-material-elevation-1;
+ }
+ paper-button[elevation='2'] {
+ @apply --paper-material-elevation-2;
+ }
+ paper-button[elevation='3'] {
+ @apply --paper-material-elevation-3;
+ }
+ paper-button[elevation='4'] {
+ @apply --paper-material-elevation-4;
+ }
+ paper-button[elevation='5'] {
+ @apply --paper-material-elevation-5;
+ }
+ /* END: Copy from paper-button */
+ paper-button:hover {
+ background: linear-gradient(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.12)),
+ var(--background-color);
+ }
+
+ /* Some mobile browsers treat focused element as hovered element.
+ As a result, element remains hovered after click (has grey background in default theme).
+ Use @media (hover:none) to remove background if
+ user's primary input mechanism can't hover over elements.
+ See: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover
+
+ Note 1: not all browsers support this media query
+ (see https://caniuse.com/#feat=css-media-interaction).
+ If browser doesn't support it, then the whole content of @media .. is ignored.
+ This is why the default behavior is placed outside of @media.
+ */
+ @media (hover: none) {
+ paper-button:hover {
+ background: transparent;
+ }
+ }
+
+ :host([primary]) {
+ --background-color: var(--primary-button-background-color);
+ --text-color: var(--primary-button-text-color);
+ }
+ :host([link][primary]) {
+ --text-color: var(--primary-button-background-color);
+ }
+
+ /* Keep below color definition for primary so that this takes precedence
+ when disabled. */
+ :host([disabled]),
+ :host([loading]) {
+ --background-color: var(--disabled-button-background-color);
+ --text-color: var(--deemphasized-text-color);
+ cursor: default;
+ }
+
+ /* Styles for link buttons specifically */
+ :host([link]) {
+ --background-color: transparent;
+ --margin: 0;
+ --padding: var(--spacing-s);
+ }
+ :host([disabled][link]),
+ :host([loading][link]) {
+ --background-color: transparent;
+ --text-color: var(--deemphasized-text-color);
+ cursor: default;
+ }
+
+ /* Styles for the optional down arrow */
+ :host(:not([down-arrow])) .downArrow {
+ display: none;
+ }
+ :host([down-arrow]) .downArrow {
+ border-top: 0.36em solid #ccc;
+ border-left: 0.36em solid transparent;
+ border-right: 0.36em solid transparent;
+ margin-bottom: var(--spacing-xxs);
+ margin-left: var(--spacing-m);
+ transition: border-top-color 200ms;
+ }
+ :host([down-arrow]) paper-button:hover .downArrow {
+ border-top-color: var(--deemphasized-text-color);
+ }
+ `,
+ ];
}
- @property({
- computed: 'computeAriaDisabled(disabled, loading)',
- reflectToAttribute: true,
- type: Boolean,
- })
- ariaDisabled!: boolean;
-
- computeAriaDisabled() {
- return this._disabled;
+ override render() {
+ return html`<paper-button
+ ?raised="${!this.link}"
+ ?disabled="${this.disabled || this.loading}"
+ role="button"
+ tabindex="-1"
+ part="paper-button"
+ class="${this.voteChip ? 'voteChip' : ''}"
+ >
+ ${this.loading ? html`<span class="loadingSpin"></span>` : ''}
+ <slot></slot>
+ <i class="downArrow"></i>
+ </paper-button>`;
}
- private readonly reporting: ReportingService = appContext.reportingService;
-
constructor() {
super();
- this._initialTabindex = this.getAttribute('tabindex') || '0';
- // TODO(TS): try avoid using unknown
- this.addEventListener('click', e =>
- this._handleAction(e as unknown as PolymerEvent)
- );
+ this.initialTabindex = this.getAttribute('tabindex') || '0';
+ this.addEventListener('click', e => this._handleAction(e));
this.addEventListener('keydown', e =>
this._handleKeydown(e as unknown as CustomKeyboardEvent)
);
}
- override ready() {
- super.ready();
- this._ensureAttribute('role', 'button');
- this._ensureAttribute('tabindex', '0');
+ override updated(changedProperties: PropertyValues) {
+ if (changedProperties.has('disabled')) {
+ this.setAttribute(
+ 'tabindex',
+ this.disabled ? '-1' : this.initialTabindex || '0'
+ );
+ }
+ if (changedProperties.has('loading') || changedProperties.has('disabled')) {
+ this.setAttribute(
+ 'aria-disabled',
+ this.disabled || this.loading ? 'true' : 'false'
+ );
+ }
}
- _handleAction(e: PolymerEvent) {
- if (this._disabled) {
+ override connectedCallback() {
+ super.connectedCallback();
+ if (!this.getAttribute('role')) {
+ this.setAttribute('role', 'button');
+ }
+ if (!this.getAttribute('tabindex')) {
+ this.setAttribute('tabindex', '0');
+ }
+ }
+
+ _handleAction(e: MouseEvent) {
+ if (this.disabled || this.loading) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
@@ -112,15 +280,6 @@
this.reporting.reportInteraction('button-click', {path: getEventPath(e)});
}
- @observe('disabled')
- _disabledChanged(disabled: boolean) {
- this.setAttribute(
- 'tabindex',
- disabled ? '-1' : this._initialTabindex || '0'
- );
- this.updateStyles();
- }
-
_handleKeydown(e: CustomKeyboardEvent) {
if (isModifierPressed(e)) {
return;
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts
deleted file mode 100644
index a15b560..0000000
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_html.ts
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style include="gr-spinner-styles">
- /* general styles for all buttons */
- :host {
- --background-color: var(
- --button-background-color,
- var(--default-button-background-color)
- );
- --text-color: var(--default-button-text-color);
- display: inline-block;
- position: relative;
- }
- :host([hidden]) {
- display: none;
- }
- :host([no-uppercase]) paper-button {
- text-transform: none;
- }
- paper-button {
- /* The next lines contains a copy of paper-button style.
- Without a copy, the @apply works incorrectly with Polymer 2.
- @apply is deprecated and is not recommended to use. It is expected
- that @apply will be replaced with the ::part CSS pseudo-element.
- After replacement copied lines can be removed.
- */
- @apply --layout-inline;
- @apply --layout-center-center;
- position: relative;
- box-sizing: border-box;
- min-width: 5.14em;
- margin: 0 0.29em;
- background: transparent;
- -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
- -webkit-tap-highlight-color: transparent;
- font: inherit;
- text-transform: uppercase;
- outline-width: 0;
- border-top-left-radius: var(--border-radius);
- border-top-right-radius: var(--border-radius);
- border-bottom-right-radius: var(--border-radius);
- border-bottom-left-radius: var(--border-radius);
- -moz-user-select: none;
- -ms-user-select: none;
- -webkit-user-select: none;
- user-select: none;
- cursor: pointer;
- z-index: 0;
- padding: var(--spacing-m);
-
- @apply --paper-font-common-base;
- @apply --paper-button;
- /* End of copy*/
-
- /* paper-button sets this to anti-aliased, which appears different than
- bold font elsewhere on macOS. */
- -webkit-font-smoothing: initial;
- align-items: center;
- background-color: var(--background-color);
- color: var(--text-color);
- display: flex;
- font-family: inherit;
- justify-content: center;
- margin: var(--margin, 0);
- min-width: var(--border, 0);
- padding: var(--padding, 4px 8px);
- @apply --gr-button;
- }
- /* https://github.com/PolymerElements/paper-button/blob/2.x/paper-button.html */
- /* BEGIN: Copy from paper-button */
- paper-button[elevation='1'] {
- @apply --paper-material-elevation-1;
- }
- paper-button[elevation='2'] {
- @apply --paper-material-elevation-2;
- }
- paper-button[elevation='3'] {
- @apply --paper-material-elevation-3;
- }
- paper-button[elevation='4'] {
- @apply --paper-material-elevation-4;
- }
- paper-button[elevation='5'] {
- @apply --paper-material-elevation-5;
- }
- /* END: Copy from paper-button */
- paper-button:hover {
- background: linear-gradient(rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.12)),
- var(--background-color);
- }
-
- /* Some mobile browsers treat focused element as hovered element.
- As a result, element remains hovered after click (has grey background in default theme).
- Use @media (hover:none) to remove background if
- user's primary input mechanism can't hover over elements.
- See: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover
-
- Note 1: not all browsers support this media query
- (see https://caniuse.com/#feat=css-media-interaction).
- If browser doesn't support it, then the whole content of @media .. is ignored.
- This is why the default behavior is placed outside of @media.
- */
- @media (hover: none) {
- paper-button:hover {
- background: transparent;
- }
- }
-
- :host([primary]) {
- --background-color: var(--primary-button-background-color);
- --text-color: var(--primary-button-text-color);
- }
- :host([link][primary]) {
- --text-color: var(--primary-button-background-color);
- }
-
- /* Keep below color definition for primary so that this takes precedence
- when disabled. */
- :host([disabled]),
- :host([loading]) {
- --background-color: var(--disabled-button-background-color);
- --text-color: var(--deemphasized-text-color);
- cursor: default;
- }
-
- /* Styles for link buttons specifically */
- :host([link]) {
- --background-color: transparent;
- --margin: 0;
- --padding: var(--spacing-s);
- }
- :host([disabled][link]),
- :host([loading][link]) {
- --background-color: transparent;
- --text-color: var(--deemphasized-text-color);
- cursor: default;
- }
-
- /* Styles for the optional down arrow */
- :host(:not([down-arrow])) .downArrow {
- display: none;
- }
- :host([down-arrow]) .downArrow {
- border-top: 0.36em solid #ccc;
- border-left: 0.36em solid transparent;
- border-right: 0.36em solid transparent;
- margin-bottom: var(--spacing-xxs);
- margin-left: var(--spacing-m);
- transition: border-top-color 200ms;
- }
- :host([down-arrow]) paper-button:hover .downArrow {
- border-top-color: var(--deemphasized-text-color);
- }
- </style>
- <paper-button
- raised="[[!link]]"
- disabled="[[_disabled]]"
- tabindex="-1"
- part="paper-button"
- >
- <template is="dom-if" if="[[loading]]">
- <span class="loadingSpin"></span>
- </template>
- <slot></slot>
- <i class="downArrow"></i>
- </paper-button>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
index f0f122a..0149bd5 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button_test.ts
@@ -17,6 +17,7 @@
import * as MockInteractions from '@polymer/iron-test-helpers/mock-interactions';
import '../../../test/common-test-setup-karma';
+import './gr-button';
import {addListener} from '@polymer/polymer/lib/utils/gestures';
import {appContext} from '../../../services/app-context';
import {html} from '@polymer/polymer/lib/utils/html-tag';
@@ -49,23 +50,26 @@
return spy;
};
- setup(() => {
+ setup(async () => {
element = basicFixture.instantiate();
+ await element.updateComplete;
});
- test('disabled is set by disabled', () => {
+ test('disabled is set by disabled', async () => {
const paperBtn = queryAndAssert<PaperButtonElement>(
element,
'paper-button'
);
assert.isFalse(paperBtn.disabled);
element.disabled = true;
+ await element.updateComplete;
assert.isTrue(paperBtn.disabled);
element.disabled = false;
+ await element.updateComplete;
assert.isFalse(paperBtn.disabled);
});
- test('loading set from listener', () => {
+ test('loading set from listener', async () => {
let resolve: Function;
element.addEventListener('click', e => {
const target = e.target as HTMLElement;
@@ -78,36 +82,44 @@
);
assert.isFalse(paperBtn.disabled);
MockInteractions.tap(element);
+ await element.updateComplete;
assert.isTrue(paperBtn.disabled);
assert.isTrue(element.hasAttribute('loading'));
resolve!();
- flush();
+ await element.updateComplete;
assert.isFalse(paperBtn.disabled);
assert.isFalse(element.hasAttribute('loading'));
});
- test('tabindex should be -1 if disabled', () => {
+ test('tabindex should be -1 if disabled', async () => {
element.disabled = true;
- assert.isTrue(element.getAttribute('tabindex') === '-1');
+ await element.updateComplete;
+ assert.equal(element.getAttribute('tabindex'), '-1');
});
// Regression tests for Issue: 11969
- test('tabindex should be reset to 0 if enabled', () => {
+ test('tabindex should be reset to 0 if enabled', async () => {
element.disabled = false;
+ await element.updateComplete;
assert.equal(element.getAttribute('tabindex'), '0');
element.disabled = true;
+ await element.updateComplete;
assert.equal(element.getAttribute('tabindex'), '-1');
element.disabled = false;
+ await element.updateComplete;
assert.equal(element.getAttribute('tabindex'), '0');
});
- test('tabindex should be preserved', () => {
+ test('tabindex should be preserved', async () => {
const tabIndexElement = tabindexFixture.instantiate() as GrButton;
tabIndexElement.disabled = false;
+ await element.updateComplete;
assert.equal(tabIndexElement.getAttribute('tabindex'), '3');
tabIndexElement.disabled = true;
+ await element.updateComplete;
assert.equal(tabIndexElement.getAttribute('tabindex'), '-1');
tabIndexElement.disabled = false;
+ await element.updateComplete;
assert.equal(tabIndexElement.getAttribute('tabindex'), '3');
});
@@ -152,8 +164,9 @@
}
suite('disabled', () => {
- setup(() => {
+ setup(async () => {
element.disabled = true;
+ await element.updateComplete;
});
for (const eventName of ['tap', 'click']) {
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
index 2ca2744b..455bd4e 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_html.ts
@@ -80,8 +80,8 @@
}
</style>
<gr-tooltip-content
- has-tooltip=""
- position-below=""
+ has-tooltip
+ position-below
title="[[tooltipText]]"
max-width="40em"
>
@@ -101,9 +101,8 @@
</a>
</template>
<template is="dom-if" if="[[!hasStatusLink(revertedChange, resolveWeblinks, status)]]">
- <div class="chip" aria-label$="Label: [[status]]">
- [[_computeStatusString(status)]]
- </div>
+ <div class="chip" aria-label$="Label: [[status]]"
+ >[[_computeStatusString(status)]]</div>
</template>
</gr-tooltip-content>
</span>
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.ts
index a56f6f1..39fc7c6 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status_test.ts
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-import sinon from 'sinon/pkg/sinon-esm';
import '../../../test/common-test-setup-karma';
import {createChange} from '../../../test/test-data-generators';
import './gr-change-status';
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 6745f58..fe4a66a 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
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-a11y-styles';
import '../../../styles/shared-styles';
import '../gr-comment/gr-comment';
import '../../diff/gr-diff/gr-diff';
@@ -56,8 +57,12 @@
import {GrButton} from '../gr-button/gr-button';
import {KnownExperimentId} from '../../../services/flags/flags';
import {DiffInfo, DiffPreferencesInfo} from '../../../types/diff';
-import {RenderPreferences} from '../../../api/diff';
-import {check, assertIsDefined} from '../../../utils/common-util';
+import {DiffLayer, RenderPreferences} from '../../../api/diff';
+import {
+ check,
+ assertIsDefined,
+ queryAndAssert,
+} from '../../../utils/common-util';
import {fireAlert, waitForEventOnce} from '../../../utils/event-util';
import {GrSyntaxLayer} from '../../diff/gr-syntax-layer/gr-syntax-layer';
import {StorageLocation} from '../../../services/storage/gr-storage';
@@ -76,8 +81,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-comment-thread')
-export class GrCommentThread extends KeyboardShortcutMixin(PolymerElement) {
+export class GrCommentThread extends base {
// KeyboardShortcutMixin Not used in this element rather other elements tests
static get template() {
@@ -197,6 +205,9 @@
@property({type: Object})
_selfAccount?: AccountDetailInfo;
+ @property({type: Array})
+ layers: DiffLayer[] = [];
+
get keyBindings() {
return {
'e shift+e': '_handleEKey',
@@ -220,6 +231,9 @@
this.addEventListener('comment-update', e =>
this._handleCommentUpdate(e as CustomEvent)
);
+ appContext.restApiService.getPreferences().then(prefs => {
+ this._initLayers(!!prefs?.disable_token_highlighting);
+ });
}
override connectedCallback() {
@@ -267,6 +281,7 @@
const resizeObserver = new ResizeObserver(
(_entries: ResizeObserverEntry[], observer: ResizeObserver) => {
if (this.offsetHeight > 0) {
+ queryAndAssert<HTMLDivElement>(this, '.comment-box').focus();
this.scrollIntoView();
}
observer.unobserve(this);
@@ -312,7 +327,6 @@
draft.__editing = true;
draft.unresolved = unresolved === false ? unresolved : true;
this.commentsService.addDraft(draft);
- this.push('comments', draft);
}
_getDiffUrlForPath(
@@ -350,14 +364,14 @@
return undefined;
}
- _getLayers(diff?: DiffInfo) {
- if (!diff) return [];
- const layers = [];
- if (this.flagsService.isEnabled(KnownExperimentId.TOKEN_HIGHLIGHTING)) {
- layers.push(new TokenHighlightLayer());
+ _initLayers(disableTokenHighlighting: boolean) {
+ if (
+ this.flagsService.isEnabled(KnownExperimentId.TOKEN_HIGHLIGHTING) &&
+ !disableTokenHighlighting
+ ) {
+ this.layers.push(new TokenHighlightLayer(this));
}
- layers.push(this.syntaxLayer);
- return layers;
+ this.layers.push(this.syntaxLayer);
}
_getUrlForViewDiff(
@@ -548,14 +562,11 @@
}
this.commentsService.addDraft(reply);
- this.push('comments', reply);
if (!isEditing) {
- // Allow the reply to render in the dom-repeat.
- setTimeout(() => {
- const commentEl = this._commentElWithDraftID(reply.__draftID);
- if (commentEl) commentEl.save();
- }, 1);
+ assertIsDefined(this.changeNum, 'changeNum');
+ assertIsDefined(this.patchNum, 'patchNum');
+ this.restApiService.saveDiffDraft(this.changeNum, this.patchNum, reply);
}
}
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 5c01467..245f71c 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
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-a11y-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
font-family: var(--font-family);
@@ -143,7 +146,10 @@
<h3 class="assistive-tech-only">
[[_computeAriaHeading(_orderedComments)]]
</h3>
- <div class$="[[_computeHostClass(unresolved, isRobotComment)]] comment-box">
+ <div
+ class$="[[_computeHostClass(unresolved, isRobotComment)]] comment-box"
+ tabindex="0"
+ >
<template
id="commentList"
is="dom-repeat"
@@ -226,7 +232,7 @@
id="diff"
change-num="[[changeNum]]"
diff="[[_diff]]"
- layers="[[_getLayers(_diff)]]"
+ layers="[[layers]]"
path="[[path]]"
prefs="[[_prefs]]"
render-prefs="[[_renderPrefs]]"
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 5f860f4..ecd9731 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
@@ -23,7 +23,6 @@
sortComments,
UIComment,
UIRobot,
- isDraft,
UIDraft,
} from '../../../utils/comment-util';
import {GrCommentThread} from './gr-comment-thread';
@@ -46,11 +45,13 @@
} from '@polymer/iron-test-helpers/mock-interactions';
import {html} from '@polymer/polymer/lib/utils/html-tag';
import {
+ mockPromise,
stubComments,
stubReporting,
stubRestApi,
} from '../../../test/test-utils';
import {_testOnly_resetState} from '../../../services/comments/comments-model';
+import {SinonStub} from 'sinon';
const basicFixture = fixtureFromElement('gr-comment-thread');
@@ -235,16 +236,14 @@
assert.equal(element._hideActions(showActions, robotComment), true);
});
- test('setting project name loads the project config', done => {
+ test('setting project name loads the project config', async () => {
const projectName = 'foo/bar/baz' as RepoName;
const getProjectStub = stubRestApi('getProjectConfig').returns(
Promise.resolve({} as ConfigInfo)
);
element.projectName = projectName;
- flush(() => {
- assert.isTrue(getProjectStub.calledWithExactly(projectName as never));
- done();
- });
+ await flush();
+ assert.isTrue(getProjectStub.calledWithExactly(projectName as never));
});
test('optionally show file path', () => {
@@ -314,10 +313,12 @@
suite('comment action tests with unresolved thread', () => {
let element: GrCommentThread;
-
+ let addDraftServiceStub: SinonStub;
+ let saveDiffDraftStub: SinonStub;
setup(() => {
+ addDraftServiceStub = stubComments('addDraft');
stubRestApi('getLoggedIn').returns(Promise.resolve(false));
- stubRestApi('saveDiffDraft').returns(
+ saveDiffDraftStub = stubRestApi('saveDiffDraft').returns(
Promise.resolve({
headers: {} as Headers,
redirected: false,
@@ -373,12 +374,11 @@
const replyBtn = element.$.replyBtn;
tap(replyBtn);
flush();
-
- const drafts = element._orderedComments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
- assert.notOk(drafts[0].message, 'message should be empty');
+ const draft = addDraftServiceStub.firstCall.args[0];
+ assert.isOk(draft);
+ assert.notOk(draft.message, 'message should be empty');
assert.equal(
- drafts[0].in_reply_to,
+ draft.in_reply_to,
'baf0414d_60047215' as UrlEncodedCommentId as UrlEncodedCommentId
);
assert.isTrue(reportStub.calledOnce);
@@ -393,11 +393,10 @@
tap(quoteBtn);
flush();
- const drafts = element._orderedComments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
- assert.equal(drafts[0].message, '> is this a crossover episode!?\n\n');
+ const draft = addDraftServiceStub.firstCall.args[0];
+ assert.equal(draft.message, '> is this a crossover episode!?\n\n');
assert.equal(
- drafts[0].in_reply_to,
+ draft.in_reply_to,
'baf0414d_60047215' as UrlEncodedCommentId as UrlEncodedCommentId
);
assert.isTrue(reportStub.calledOnce);
@@ -427,20 +426,16 @@
tap(quoteBtn);
flush();
- const drafts = element._orderedComments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
+ const draft = addDraftServiceStub.firstCall.args[0];
assert.equal(
- drafts[0].message,
+ draft.message,
'> is this a crossover episode!?\n> It might be!\n\n'
);
- assert.equal(
- drafts[0].in_reply_to,
- 'baf0414d_60047215' as UrlEncodedCommentId
- );
+ assert.equal(draft.in_reply_to, 'baf0414d_60047215' as UrlEncodedCommentId);
assert.isTrue(reportStub.calledOnce);
});
- test('ack', done => {
+ test('ack', async () => {
const reportStub = stubReporting('recordDraftInteraction');
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
@@ -451,22 +446,17 @@
const ackBtn = element.shadowRoot?.querySelector('#ackBtn');
assert.isOk(ackBtn);
tap(ackBtn!);
- flush(() => {
- const drafts = element.comments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
- assert.equal(drafts[0].message, 'Ack');
- assert.equal(
- drafts[0].in_reply_to,
- 'baf0414d_60047215' as UrlEncodedCommentId
- );
- assert.equal(drafts[0].unresolved, false);
- assert.isTrue(reportStub.calledOnce);
- done();
- });
+ await flush();
+ const draft = addDraftServiceStub.firstCall.args[0];
+ assert.equal(draft.message, 'Ack');
+ assert.equal(draft.in_reply_to, 'baf0414d_60047215' as UrlEncodedCommentId);
+ assert.equal(draft.unresolved, false);
+ assert.isTrue(reportStub.calledOnce);
});
- test('done', done => {
+ test('done', async () => {
const reportStub = stubReporting('recordDraftInteraction');
+ assert.isFalse(saveDiffDraftStub.called);
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
const commentEl = element.shadowRoot?.querySelector('gr-comment');
@@ -475,21 +465,16 @@
const doneBtn = element.shadowRoot?.querySelector('#doneBtn');
assert.isOk(doneBtn);
tap(doneBtn!);
- flush(() => {
- const drafts = element.comments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
- assert.equal(drafts[0].message, 'Done');
- assert.equal(
- drafts[0].in_reply_to,
- 'baf0414d_60047215' as UrlEncodedCommentId
- );
- assert.isFalse(drafts[0].unresolved);
- assert.isTrue(reportStub.calledOnce);
- done();
- });
+ await flush();
+ const draft = addDraftServiceStub.firstCall.args[0];
+ assert.equal(draft.message, 'Done');
+ assert.equal(draft.in_reply_to, 'baf0414d_60047215' as UrlEncodedCommentId);
+ assert.isFalse(draft.unresolved);
+ assert.isTrue(reportStub.calledOnce);
+ assert.isTrue(saveDiffDraftStub.called);
});
- test('save', done => {
+ test('save', async () => {
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
element.path = '/path/to/file.txt';
@@ -498,30 +483,28 @@
element.shadowRoot?.querySelector('gr-comment')?._fireSave();
- flush(() => {
- assert.equal(element.rootId, 'baf0414d_60047215' as UrlEncodedCommentId);
- done();
- });
+ await flush();
+ assert.equal(element.rootId, 'baf0414d_60047215' as UrlEncodedCommentId);
});
- test('please fix', done => {
+ test('please fix', async () => {
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
const commentEl = element.shadowRoot?.querySelector('gr-comment');
assert.ok(commentEl);
+ const promise = mockPromise();
commentEl!.addEventListener('create-fix-comment', () => {
- const drafts = element._orderedComments.filter(c => isDraft(c));
- assert.equal(drafts.length, 1);
+ const draft = addDraftServiceStub.firstCall.args[0];
assert.equal(
- drafts[0].message,
+ draft.message,
'> is this a crossover episode!?\n\nPlease fix.'
);
assert.equal(
- drafts[0].in_reply_to,
+ draft.in_reply_to,
'baf0414d_60047215' as UrlEncodedCommentId
);
- assert.isTrue(drafts[0].unresolved);
- done();
+ assert.isTrue(draft.unresolved);
+ promise.resolve();
});
commentEl!.dispatchEvent(
new CustomEvent('create-fix-comment', {
@@ -530,9 +513,10 @@
bubbles: false,
})
);
+ await promise;
});
- test('discard', done => {
+ test('discard', async () => {
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
element.path = '/path/to/file.txt';
@@ -545,37 +529,43 @@
'it’s pronouced jiff, not giff'
)
);
- flush();
+ await flush();
const draftEl = element.root?.querySelectorAll('gr-comment')[1];
assert.ok(draftEl);
draftEl?._fireSave(); // tell the model about the draft
+ const promise = mockPromise();
draftEl!.addEventListener('comment-discard', () => {
- flush();
assert.isTrue(deleteDraftStub.called);
- done();
+ promise.resolve();
});
draftEl!._fireDiscard();
+ await promise;
});
- test('discard with a single comment still fires event with previous rootId', done => {
+ test('discard with a single comment still fires event with previous rootId', async () => {
element.changeNum = 42 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
element.path = '/path/to/file.txt';
element.comments = [];
element.addOrEditDraft(1 as LineNumber);
+ const draft = addDraftServiceStub.firstCall.args[0];
+ element.comments = [draft];
flush();
const rootId = element.rootId;
assert.isOk(rootId);
-
+ flush();
const draftEl = element.root?.querySelectorAll('gr-comment')[0];
assert.ok(draftEl);
const deleteDraftStub = stubComments('deleteDraft');
+ const promise = mockPromise();
draftEl!.addEventListener('comment-discard', () => {
assert.isTrue(deleteDraftStub.called);
- done();
+ promise.resolve();
});
draftEl!._fireDiscard();
+ await promise;
+ assert.isTrue(deleteDraftStub.called);
});
test('comment-update', () => {
@@ -644,6 +634,8 @@
test('comment in_reply_to is either null or most recent comment', () => {
element._createReplyComment('dummy', true);
+ const draft = addDraftServiceStub.firstCall.args[0];
+ element.comments = [...element.comments, draft];
flush();
assert.equal(element._orderedComments.length, 5);
assert.equal(
@@ -655,6 +647,8 @@
test('resolvable comments', () => {
assert.isFalse(element.unresolved);
element._createReplyComment('dummy', true, true);
+ const draft = addDraftServiceStub.firstCall.args[0];
+ element.comments = [...element.comments, draft];
flush();
assert.isTrue(element.unresolved);
});
@@ -703,18 +697,23 @@
test('addDraft sets unresolved state correctly', () => {
let unresolved = true;
+ let draft;
element.comments = [];
element.path = 'abcd';
element.addDraft(undefined, undefined, unresolved);
- assert.equal(element.comments[0].unresolved, true);
+ draft = addDraftServiceStub.lastCall.args[0];
+ assert.equal(draft.unresolved, true);
unresolved = false; // comment should get added as actually resolved.
element.comments = [];
element.addDraft(undefined, undefined, unresolved);
- assert.equal(element.comments[0].unresolved, false);
+ draft = addDraftServiceStub.lastCall.args[0];
+ assert.equal(draft.unresolved, false);
+
element.comments = [];
element.addDraft();
- assert.equal(element.comments[0].unresolved, true);
+ draft = addDraftServiceStub.lastCall.args[0];
+ assert.equal(draft.unresolved, true);
});
test('_newDraft with root', () => {
@@ -734,13 +733,16 @@
element.comments = [];
element.path = 'abcd';
element.addOrEditDraft(1);
+ const draft = addDraftServiceStub.firstCall.args[0];
+ element.comments = [draft];
+ flush();
assert.equal(element.comments.length, 1);
// Mock a submitted comment.
element.comments[0].id = (element.comments[0] as UIDraft)
.__draftID as UrlEncodedCommentId;
delete (element.comments[0] as UIDraft).__draft;
element.addOrEditDraft(1);
- assert.equal(element.comments.length, 2);
+ assert.equal(addDraftServiceStub.callCount, 2);
});
test('unresolved label', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index 2c2d454..fa04860 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -20,7 +20,6 @@
import '../../plugins/gr-endpoint-param/gr-endpoint-param';
import '../gr-button/gr-button';
import '../gr-dialog/gr-dialog';
-import '../gr-date-formatter/gr-date-formatter';
import '../gr-formatted-text/gr-formatted-text';
import '../gr-icons/gr-icons';
import '../gr-overlay/gr-overlay';
@@ -100,8 +99,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-comment')
-export class GrComment extends KeyboardShortcutMixin(PolymerElement) {
+export class GrComment extends base {
static get template() {
return htmlTemplate;
}
@@ -125,6 +127,12 @@
*/
/**
+ * Fired when this comment is edited.
+ *
+ * @event comment-edit
+ */
+
+ /**
* Fired when this comment is saved.
*
* @event comment-save
@@ -548,6 +556,17 @@
return {comment: this.comment, patchNum: this.patchNum};
}
+ _fireEdit() {
+ if (this.comment) this.commentsService.editDraft(this.comment);
+ this.dispatchEvent(
+ new CustomEvent('comment-edit', {
+ detail: this._getEventPayload(),
+ composed: true,
+ bubbles: true,
+ })
+ );
+ }
+
_fireSave() {
if (this.comment) this.commentsService.addDraft(this.comment);
this.dispatchEvent(
@@ -655,11 +674,21 @@
@observe('comment.message')
_commentMessageChanged(message: string) {
- this._messageText = message || '';
+ /*
+ * Only overwrite the message text user has typed if there is no existing
+ * text typed by the user. This prevents the bug where creating another
+ * comment triggered a recomputation of comments and the text written by
+ * the user was lost.
+ */
+ if (!this._messageText) this._messageText = message || '';
}
_messageTextChanged(_: string, oldValue: string) {
- if (!this.comment || (this.comment && this.comment.id)) {
+ // Only store comments that are being edited in local storage.
+ if (
+ !this.comment ||
+ (this.comment.id && (!isDraft(this.comment) || !this.comment.__editing))
+ ) {
return;
}
@@ -667,33 +696,32 @@
? this.comment.patch_set
: this._getPatchNum();
const {path, line, range} = this.comment;
- if (path) {
- this.storeTask = debounce(
- this.storeTask,
- () => {
- const message = this._messageText;
- if (this.changeNum === undefined) {
- throw new Error('undefined changeNum');
- }
- const commentLocation: StorageLocation = {
- changeNum: this.changeNum,
- patchNum,
- path,
- line,
- range,
- };
+ if (!path) return;
+ this.storeTask = debounce(
+ this.storeTask,
+ () => {
+ const message = this._messageText;
+ if (this.changeNum === undefined) {
+ throw new Error('undefined changeNum');
+ }
+ const commentLocation: StorageLocation = {
+ changeNum: this.changeNum,
+ patchNum,
+ path,
+ line,
+ range,
+ };
- if ((!message || !message.length) && oldValue) {
- // If the draft has been modified to be empty, then erase the storage
- // entry.
- this.storage.eraseDraftComment(commentLocation);
- } else {
- this.storage.setDraftComment(commentLocation, message);
- }
- },
- STORAGE_DEBOUNCE_INTERVAL
- );
- }
+ if ((!message || !message.length) && oldValue) {
+ // If the draft has been modified to be empty, then erase the storage
+ // entry.
+ this.storage.eraseDraftComment(commentLocation);
+ } else {
+ this.storage.setDraftComment(commentLocation, message);
+ }
+ },
+ STORAGE_DEBOUNCE_INTERVAL
+ );
}
_handleAnchorClick(e: Event) {
@@ -715,6 +743,7 @@
e.preventDefault();
if (this.comment?.message) this._messageText = this.comment.message;
this.editing = true;
+ this._fireEdit();
this.reporting.recordDraftInteraction();
}
@@ -722,9 +751,7 @@
e.preventDefault();
// Ignore saves started while already saving.
- if (this.disabled) {
- return;
- }
+ if (this.disabled) return;
const timingLabel = this.comment?.id
? REPORT_UPDATE_DRAFT
: REPORT_CREATE_DRAFT;
@@ -737,17 +764,16 @@
_handleCancel(e: Event) {
e.preventDefault();
-
- if (
- !this.comment?.message ||
- this.comment.message.trim().length === 0 ||
- !this.comment.id
- ) {
+ if (!this.comment) return;
+ if (!this.comment.id) {
+ // Ensures we update the discarded draft message before deleting the draft
+ this.set('comment.message', this._messageText);
this._fireDiscard();
- return;
+ } else {
+ this.set('comment.__editing', false);
+ this.commentsService.cancelDraft(this.comment);
+ this.editing = false;
}
- this._messageText = this.comment.message;
- this.editing = false;
}
_fireDiscard() {
@@ -947,9 +973,15 @@
return;
}
- // Only apply local drafts to comments that haven't been saved
- // remotely, and haven't been given a default message already.
- if (!comment || comment.id || comment.message || !comment.path) {
+ // Only apply local drafts to comments that are drafts and are currently
+ // being edited.
+ if (
+ !comment ||
+ !comment.path ||
+ comment.message ||
+ !isDraft(comment) ||
+ !comment.__editing
+ ) {
return;
}
@@ -962,7 +994,7 @@
});
if (draft) {
- this.set('comment.message', draft.message);
+ this._messageText = draft.message || '';
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
index b00bf8b..d1496fb 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
@@ -275,10 +275,10 @@
</template>
<gr-tooltip-content
class="draftTooltip"
- has-tooltip=""
+ has-tooltip
title="[[_computeDraftTooltip(_unableToSave)]]"
max-width="20em"
- show-icon=""
+ show-icon
>
<span class="draftLabel">[[_computeDraftText(_unableToSave)]]</span>
</gr-tooltip-content>
@@ -313,7 +313,7 @@
<template is="dom-if" if="[[comment.updated]]">
<span class="date" tabindex="0" on-click="_handleAnchorClick">
<gr-date-formatter
- has-tooltip=""
+ withTooltip
date-str="[[comment.updated]]"
></gr-date-formatter>
</span>
@@ -357,7 +357,7 @@
<div class="respectfulReviewTip">
<div>
<gr-tooltip-content
- has-tooltip=""
+ has-tooltip
title="Tips for respectful code reviews."
>
<iron-icon
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
index cb09125..b963d4b 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.ts
@@ -28,6 +28,7 @@
query,
isVisible,
stubReporting,
+ mockPromise,
} from '../../../test/test-utils';
import {
AccountId,
@@ -51,7 +52,7 @@
createFixSuggestionInfo,
} from '../../../test/test-data-generators';
import {Timer} from '../../../services/gr-reporting/gr-reporting';
-import {SinonFakeTimers, SinonStubbedMember} from 'sinon/pkg/sinon-esm';
+import {SinonFakeTimers, SinonStubbedMember} from 'sinon';
import {CreateFixCommentEvent} from '../../../types/events';
import {DraftInfo, UIRobot} from '../../../utils/comment-util';
import {MockTimer} from '../../../services/gr-reporting/gr-reporting_mock';
@@ -155,7 +156,7 @@
});
});
- test('message is not retrieved from storage when other edits', done => {
+ test('message is not retrieved from storage when missing path', async () => {
const storageStub = stubStorage('getDraftComment');
const loadSpy = sinon.spy(element, '_loadLocalDraft');
@@ -168,14 +169,34 @@
},
line: 5,
};
- flush(() => {
- assert.isTrue(loadSpy.called);
- assert.isFalse(storageStub.called);
- done();
- });
+ await flush();
+ assert.isTrue(loadSpy.called);
+ assert.isFalse(storageStub.called);
});
- test('message is retrieved from storage when no other edits', done => {
+ test('message is not retrieved from storage when message present', async () => {
+ const storageStub = stubStorage('getDraftComment');
+ const loadSpy = sinon.spy(element, '_loadLocalDraft');
+
+ element.changeNum = 1 as NumericChangeId;
+ element.patchNum = 1 as PatchSetNum;
+ element.comment = {
+ author: {
+ name: 'Mr. Peanutbutter',
+ email: 'tenn1sballchaser@aol.com' as EmailAddress,
+ },
+ message: 'This is a message',
+ line: 5,
+ path: 'test',
+ __editing: true,
+ __draft: true,
+ };
+ await flush();
+ assert.isTrue(loadSpy.called);
+ assert.isFalse(storageStub.called);
+ });
+
+ test('message is retrieved from storage for drafts in edit', async () => {
const storageStub = stubStorage('getDraftComment');
const loadSpy = sinon.spy(element, '_loadLocalDraft');
@@ -188,12 +209,35 @@
},
line: 5,
path: 'test',
+ __editing: true,
+ __draft: true,
};
- flush(() => {
- assert.isTrue(loadSpy.called);
- assert.isTrue(storageStub.called);
- done();
- });
+ await flush();
+ assert.isTrue(loadSpy.called);
+ assert.isTrue(storageStub.called);
+ });
+
+ test('comment message sets messageText only when empty', () => {
+ element.changeNum = 1 as NumericChangeId;
+ element.patchNum = 1 as PatchSetNum;
+ element._messageText = '';
+ element.comment = {
+ author: {
+ name: 'Mr. Peanutbutter',
+ email: 'tenn1sballchaser@aol.com' as EmailAddress,
+ },
+ line: 5,
+ path: 'test',
+ __editing: true,
+ __draft: true,
+ message: 'hello world',
+ };
+ // messageText was empty so overwrite the message now
+ assert.equal(element._messageText, 'hello world');
+
+ element.comment!.message = 'new message';
+ // messageText was already set so do not overwrite it
+ assert.equal(element._messageText, 'hello world');
});
test('_getPatchNum', () => {
@@ -315,7 +359,7 @@
);
});
- test('delete comment', done => {
+ test('delete comment', async () => {
const stub = stubRestApi('deleteComment').returns(
Promise.resolve({
id: '1' as UrlEncodedCommentId,
@@ -333,24 +377,21 @@
)
);
tap(queryAndAssert(element, '.action.delete'));
- flush(() => {
- openSpy.lastCall.returnValue.then(() => {
- const dialog = element.confirmDeleteOverlay?.querySelector(
- '#confirmDeleteComment'
- ) as GrConfirmDeleteCommentDialog;
- dialog.message = 'removal reason';
- element._handleConfirmDeleteComment();
- assert.isTrue(
- stub.calledWith(
- 42 as NumericChangeId,
- 1 as PatchSetNum,
- 'baf0414d_60047215' as UrlEncodedCommentId,
- 'removal reason'
- )
- );
- done();
- });
- });
+ await flush();
+ await openSpy.lastCall.returnValue;
+ const dialog = element.confirmDeleteOverlay?.querySelector(
+ '#confirmDeleteComment'
+ ) as GrConfirmDeleteCommentDialog;
+ dialog.message = 'removal reason';
+ element._handleConfirmDeleteComment();
+ assert.isTrue(
+ stub.calledWith(
+ 42 as NumericChangeId,
+ 1 as PatchSetNum,
+ 'baf0414d_60047215' as UrlEncodedCommentId,
+ 'removal reason'
+ )
+ );
});
suite('draft update reporting', () => {
@@ -417,6 +458,7 @@
test('edit reports interaction', () => {
const reportStub = stubReporting('recordDraftInteraction');
+ sinon.stub(element, '_fireEdit');
element.draft = true;
flush();
tap(queryAndAssert(element, '.edit'));
@@ -437,7 +479,7 @@
assert.isTrue(reportStub.calledOnce);
});
- test('failed save draft request', done => {
+ test('failed save draft request', async () => {
element.draft = true;
element.changeNum = 1 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
@@ -449,46 +491,42 @@
...createComment(),
id: 'abc_123' as UrlEncodedCommentId,
});
- flush(() => {
- let args = updateRequestStub.lastCall.args;
- assert.deepEqual(args, [0, true]);
- assert.equal(
- element._getSavingMessage(...args),
- __testOnly_UNSAVED_MESSAGE
- );
- assert.equal(
- (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
- 'DRAFT(Failed to save)'
- );
- assert.isTrue(
- isVisible(queryAndAssert(element, '.save')),
- 'save is visible'
- );
- diffDraftStub.returns(Promise.resolve({...new Response(), ok: true}));
- element._saveDraft({
- ...createComment(),
- id: 'abc_123' as UrlEncodedCommentId,
- });
- flush(() => {
- args = updateRequestStub.lastCall.args;
- assert.deepEqual(args, [0]);
- assert.equal(element._getSavingMessage(...args), 'All changes saved');
- assert.equal(
- (queryAndAssert(element, '.draftLabel') as HTMLSpanElement)
- .innerText,
- 'DRAFT'
- );
- assert.isFalse(
- isVisible(queryAndAssert(element, '.save')),
- 'save is not visible'
- );
- assert.isFalse(element._unableToSave);
- done();
- });
+ await flush();
+ let args = updateRequestStub.lastCall.args;
+ assert.deepEqual(args, [0, true]);
+ assert.equal(
+ element._getSavingMessage(...args),
+ __testOnly_UNSAVED_MESSAGE
+ );
+ assert.equal(
+ (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
+ 'DRAFT(Failed to save)'
+ );
+ assert.isTrue(
+ isVisible(queryAndAssert(element, '.save')),
+ 'save is visible'
+ );
+ diffDraftStub.returns(Promise.resolve({...new Response(), ok: true}));
+ element._saveDraft({
+ ...createComment(),
+ id: 'abc_123' as UrlEncodedCommentId,
});
+ await flush();
+ args = updateRequestStub.lastCall.args;
+ assert.deepEqual(args, [0]);
+ assert.equal(element._getSavingMessage(...args), 'All changes saved');
+ assert.equal(
+ (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
+ 'DRAFT'
+ );
+ assert.isFalse(
+ isVisible(queryAndAssert(element, '.save')),
+ 'save is not visible'
+ );
+ assert.isFalse(element._unableToSave);
});
- test('failed save draft request with promise failure', done => {
+ test('failed save draft request with promise failure', async () => {
element.draft = true;
element.changeNum = 1 as NumericChangeId;
element.patchNum = 1 as PatchSetNum;
@@ -500,43 +538,39 @@
...createComment(),
id: 'abc_123' as UrlEncodedCommentId,
});
- flush(() => {
- let args = updateRequestStub.lastCall.args;
- assert.deepEqual(args, [0, true]);
- assert.equal(
- element._getSavingMessage(...args),
- __testOnly_UNSAVED_MESSAGE
- );
- assert.equal(
- (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
- 'DRAFT(Failed to save)'
- );
- assert.isTrue(
- isVisible(queryAndAssert(element, '.save')),
- 'save is visible'
- );
- diffDraftStub.returns(Promise.resolve({...new Response(), ok: true}));
- element._saveDraft({
- ...createComment(),
- id: 'abc_123' as UrlEncodedCommentId,
- });
- flush(() => {
- args = updateRequestStub.lastCall.args;
- assert.deepEqual(args, [0]);
- assert.equal(element._getSavingMessage(...args), 'All changes saved');
- assert.equal(
- (queryAndAssert(element, '.draftLabel') as HTMLSpanElement)
- .innerText,
- 'DRAFT'
- );
- assert.isFalse(
- isVisible(queryAndAssert(element, '.save')),
- 'save is not visible'
- );
- assert.isFalse(element._unableToSave);
- done();
- });
+ await flush();
+ let args = updateRequestStub.lastCall.args;
+ assert.deepEqual(args, [0, true]);
+ assert.equal(
+ element._getSavingMessage(...args),
+ __testOnly_UNSAVED_MESSAGE
+ );
+ assert.equal(
+ (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
+ 'DRAFT(Failed to save)'
+ );
+ assert.isTrue(
+ isVisible(queryAndAssert(element, '.save')),
+ 'save is visible'
+ );
+ diffDraftStub.returns(Promise.resolve({...new Response(), ok: true}));
+ element._saveDraft({
+ ...createComment(),
+ id: 'abc_123' as UrlEncodedCommentId,
});
+ await flush();
+ args = updateRequestStub.lastCall.args;
+ assert.deepEqual(args, [0]);
+ assert.equal(element._getSavingMessage(...args), 'All changes saved');
+ assert.equal(
+ (queryAndAssert(element, '.draftLabel') as HTMLSpanElement).innerText,
+ 'DRAFT'
+ );
+ assert.isFalse(
+ isVisible(queryAndAssert(element, '.save')),
+ 'save is not visible'
+ );
+ assert.isFalse(element._unableToSave);
});
});
@@ -579,10 +613,11 @@
__draftID: 'temp_draft_id',
path: '/path/to/file',
line: 5,
+ id: undefined,
};
});
- test('button visibility states', () => {
+ test('button visibility states', async () => {
element.showActions = false;
assert.isTrue(
queryAndAssert(element, '.humanActions').hasAttribute('hidden')
@@ -600,7 +635,7 @@
);
element.draft = true;
- flush();
+ await flush();
assert.isTrue(
isVisible(queryAndAssert(element, '.edit')),
'edit is visible'
@@ -629,7 +664,7 @@
);
element.editing = true;
- flush();
+ await flush();
assert.isFalse(
isVisible(queryAndAssert(element, '.edit')),
'edit is not visible'
@@ -659,7 +694,7 @@
element.draft = false;
element.editing = false;
- flush();
+ await flush();
assert.isFalse(
isVisible(queryAndAssert(element, '.edit')),
'edit is not visible'
@@ -686,7 +721,7 @@
element.comment!.id = 'foo' as UrlEncodedCommentId;
element.draft = true;
element.editing = true;
- flush();
+ await flush();
assert.isTrue(
isVisible(queryAndAssert(element, '.cancel')),
'cancel is visible'
@@ -726,14 +761,14 @@
element.set(['comment', 'robot_run_id'], 'text');
element.editing = false;
element.collapsed = false;
- flush();
+ await flush();
assert.isTrue(
queryAndAssert(element, '.robotRun.link').textContent === 'Run Details'
);
// A robot comment with run ID and url should display a link.
element.set(['comment', 'url'], '/path/to/run');
- flush();
+ await flush();
assert.notEqual(
getComputedStyle(queryAndAssert(element, '.robotRun.link')).display,
'none'
@@ -745,7 +780,8 @@
);
});
- test('collapsible drafts', () => {
+ test('collapsible drafts', async () => {
+ const fireEditStub = sinon.stub(element, '_fireEdit');
assert.isTrue(element.collapsed);
assert.isFalse(
isVisible(queryAndAssert(element, 'gr-formatted-text')),
@@ -780,9 +816,10 @@
// When the edit button is pressed, should still see the actions
// and also textarea
element.draft = true;
- flush();
+ await flush();
tap(queryAndAssert(element, '.edit'));
- flush();
+ await flush();
+ assert.isTrue(fireEditStub.called);
assert.isFalse(element.collapsed);
assert.isFalse(
isVisible(queryAndAssert(element, 'gr-formatted-text')),
@@ -837,7 +874,7 @@
);
});
- test('robot comment layout', done => {
+ test('robot comment layout', async () => {
const comment = {
robot_id: 'happy_robot_id' as RobotId,
url: '/robot/comment',
@@ -849,36 +886,32 @@
};
element.comment = comment;
element.collapsed = false;
- flush(() => {
- let runIdMessage;
- runIdMessage = queryAndAssert(element, '.runIdMessage') as HTMLElement;
- assert.isFalse((runIdMessage as HTMLElement).hidden);
+ await flush;
+ let runIdMessage;
+ runIdMessage = queryAndAssert(element, '.runIdMessage') as HTMLElement;
+ assert.isFalse((runIdMessage as HTMLElement).hidden);
- const runDetailsLink = queryAndAssert(
- element,
- '.robotRunLink'
- ) as HTMLAnchorElement;
- assert.isTrue(
- runDetailsLink.href.indexOf((element.comment as UIRobot).url!) !== -1
- );
+ const runDetailsLink = queryAndAssert(
+ element,
+ '.robotRunLink'
+ ) as HTMLAnchorElement;
+ assert.isTrue(
+ runDetailsLink.href.indexOf((element.comment as UIRobot).url!) !== -1
+ );
- const robotServiceName = queryAndAssert(element, '.robotName');
- assert.equal(robotServiceName.textContent?.trim(), 'happy_robot_id');
+ const robotServiceName = queryAndAssert(element, '.robotName');
+ assert.equal(robotServiceName.textContent?.trim(), 'happy_robot_id');
- const authorName = queryAndAssert(element, '.robotId');
- assert.isTrue(
- (authorName as HTMLDivElement).innerText === 'Happy Robot'
- );
+ const authorName = queryAndAssert(element, '.robotId');
+ assert.isTrue((authorName as HTMLDivElement).innerText === 'Happy Robot');
- element.collapsed = true;
- flush();
- runIdMessage = queryAndAssert(element, '.runIdMessage');
- assert.isTrue((runIdMessage as HTMLDivElement).hidden);
- done();
- });
+ element.collapsed = true;
+ await flush();
+ runIdMessage = queryAndAssert(element, '.runIdMessage');
+ assert.isTrue((runIdMessage as HTMLDivElement).hidden);
});
- test('author name fallback to email', done => {
+ test('author name fallback to email', async () => {
const comment = {
url: '/robot/comment',
author: {
@@ -888,17 +921,16 @@
};
element.comment = comment;
element.collapsed = false;
- flush(() => {
- const authorName = queryAndAssert(
- queryAndAssert(element, 'gr-account-label'),
- 'span.name'
- ) as HTMLSpanElement;
- assert.equal(authorName.innerText.trim(), 'test@test.com');
- done();
- });
+ await flush();
+ const authorName = queryAndAssert(
+ queryAndAssert(element, 'gr-account-label'),
+ 'span.name'
+ ) as HTMLSpanElement;
+ assert.equal(authorName.innerText.trim(), 'test@test.com');
});
- test('patchset level comment', done => {
+ test('patchset level comment', async () => {
+ const fireEditStub = sinon.stub(element, '_fireEdit');
const comment = {
...element.comment,
path: SpecialFilePath.PATCHSET_LEVEL_COMMENTS,
@@ -906,25 +938,26 @@
range: undefined,
};
element.comment = comment;
- flush();
+ await flush();
tap(queryAndAssert(element, '.edit'));
+ assert.isTrue(fireEditStub.called);
assert.isTrue(element.editing);
element._messageText = 'hello world';
const eraseMessageDraftSpy = spyStorage('eraseDraftComment');
const mockEvent = {...new Event('click'), preventDefault: sinon.stub()};
element._handleSave(mockEvent);
- flush(() => {
- assert.isTrue(eraseMessageDraftSpy.called);
- done();
- });
+ await flush();
+ assert.isTrue(eraseMessageDraftSpy.called);
});
- test('draft creation/cancellation', done => {
+ test('draft creation/cancellation', async () => {
+ const fireEditStub = sinon.stub(element, '_fireEdit');
assert.isFalse(element.editing);
element.draft = true;
- flush();
+ await flush();
tap(queryAndAssert(element, '.edit'));
+ assert.isTrue(fireEditStub.called);
assert.isTrue(element.editing);
element.comment!.message = '';
@@ -945,37 +978,41 @@
element.addEventListener('comment-update', updateStub);
let numDiscardEvents = 0;
+ const promise = mockPromise();
element.addEventListener('comment-discard', () => {
numDiscardEvents++;
assert.isFalse(eraseMessageDraftSpy.called);
if (numDiscardEvents === 2) {
assert.isFalse(updateStub.called);
- done();
+ promise.resolve();
}
});
tap(queryAndAssert(element, '.cancel'));
- flush();
+ await flush();
element._messageText = '';
element.editing = true;
- flush();
+ await flush();
pressAndReleaseKeyOn(element.textarea!, 27); // esc
+ await promise;
});
- test('draft discard removes message from storage', done => {
+ test('draft discard removes message from storage', async () => {
element._messageText = '';
const eraseMessageDraftSpy = sinon.spy(
element,
'_eraseDraftCommentFromStorage'
);
+ const promise = mockPromise();
element.addEventListener('comment-discard', () => {
assert.isTrue(eraseMessageDraftSpy.called);
- done();
+ promise.resolve();
});
element._handleDiscard({
...new Event('click'),
preventDefault: sinon.stub(),
});
+ await promise;
});
test('storage is cleared only after save success', () => {
@@ -1022,22 +1059,24 @@
assert.equal(element._computeSaveDisabled('', comment, false), true);
});
- test('ctrl+s saves comment', done => {
+ test('ctrl+s saves comment', async () => {
+ const promise = mockPromise();
const stub = sinon.stub(element, 'save').callsFake(() => {
assert.isTrue(stub.called);
stub.restore();
- done();
+ promise.resolve();
return Promise.resolve();
});
element._messageText = 'is that the horse from horsing around??';
element.editing = true;
- flush();
+ await flush();
pressAndReleaseKeyOn(element.textarea!.$.textarea.textarea, 83, 'ctrl'); // 'ctrl + s'
+ await promise;
});
- test('draft saving/editing', done => {
+ test('draft saving/editing', async () => {
const dispatchEventStub = sinon.stub(element, 'dispatchEvent');
-
+ const fireEditStub = sinon.stub(element, '_fireEdit');
const clock: SinonFakeTimers = sinon.useFakeTimers();
const tickAndFlush = async (repetitions: number) => {
for (let i = 1; i <= repetitions; i++) {
@@ -1047,8 +1086,9 @@
};
element.draft = true;
- flush();
+ await flush();
tap(queryAndAssert(element, '.edit'));
+ assert.isTrue(fireEditStub.called);
tickAndFlush(1);
element._messageText = 'good news, everyone!';
tickAndFlush(1);
@@ -1056,7 +1096,7 @@
assert.isTrue(dispatchEventStub.calledTwice);
element._messageText = 'good news, everyone!';
- flush();
+ await flush();
assert.isTrue(dispatchEventStub.calledTwice);
tap(queryAndAssert(element, '.save'));
@@ -1066,68 +1106,62 @@
'Element should be disabled when creating draft.'
);
- element
- ._xhrPromise!.then(draft => {
- const evt = dispatchEventStub.lastCall.args[0] as CustomEvent<{
- comment: DraftInfo;
- }>;
- assert.equal(evt.type, 'comment-save');
+ let draft = await element._xhrPromise!;
+ const evt = dispatchEventStub.lastCall.args[0] as CustomEvent<{
+ comment: DraftInfo;
+ }>;
+ assert.equal(evt.type, 'comment-save');
- const expectedDetail = {
- comment: {
- ...createComment(),
- __draft: true,
- __draftID: 'temp_draft_id',
- id: 'baf0414d_40572e03' as UrlEncodedCommentId,
- line: 5,
- message: 'saved!',
- path: '/path/to/file',
- updated: '2015-12-08 21:52:36.177000000' as Timestamp,
- },
- patchNum: 1 as PatchSetNum,
- };
+ const expectedDetail = {
+ comment: {
+ ...createComment(),
+ __draft: true,
+ __draftID: 'temp_draft_id',
+ id: 'baf0414d_40572e03' as UrlEncodedCommentId,
+ line: 5,
+ message: 'saved!',
+ path: '/path/to/file',
+ updated: '2015-12-08 21:52:36.177000000' as Timestamp,
+ },
+ patchNum: 1 as PatchSetNum,
+ };
- assert.deepEqual(evt.detail, expectedDetail);
- assert.isFalse(
- element.disabled,
- 'Element should be enabled when done creating draft.'
- );
- assert.equal(draft.message, 'saved!');
- assert.isFalse(element.editing);
- })
- .then(() => {
- tap(queryAndAssert(element, '.edit'));
- element._messageText =
- 'You’ll be delivering a package to Chapek 9, ' +
- 'a world where humans are killed on sight.';
- tap(queryAndAssert(element, '.save'));
- assert.isTrue(
- element.disabled,
- 'Element should be disabled when updating draft.'
- );
-
- element._xhrPromise!.then(draft => {
- assert.isFalse(
- element.disabled,
- 'Element should be enabled when done updating draft.'
- );
- assert.equal(draft.message, 'saved!');
- assert.isFalse(element.editing);
- dispatchEventStub.restore();
- done();
- });
- });
+ assert.deepEqual(evt.detail, expectedDetail);
+ assert.isFalse(
+ element.disabled,
+ 'Element should be enabled when done creating draft.'
+ );
+ assert.equal(draft.message, 'saved!');
+ assert.isFalse(element.editing);
+ tap(queryAndAssert(element, '.edit'));
+ assert.isTrue(fireEditStub.calledTwice);
+ element._messageText =
+ 'You’ll be delivering a package to Chapek 9, ' +
+ 'a world where humans are killed on sight.';
+ tap(queryAndAssert(element, '.save'));
+ assert.isTrue(
+ element.disabled,
+ 'Element should be disabled when updating draft.'
+ );
+ draft = await element._xhrPromise!;
+ assert.isFalse(
+ element.disabled,
+ 'Element should be enabled when done updating draft.'
+ );
+ assert.equal(draft.message, 'saved!');
+ assert.isFalse(element.editing);
+ dispatchEventStub.restore();
});
- test('draft prevent save when disabled', () => {
+ test('draft prevent save when disabled', async () => {
const saveStub = sinon.stub(element, 'save').returns(Promise.resolve());
element.showActions = true;
element.draft = true;
- flush();
+ await flush();
tap(element.$.header);
tap(queryAndAssert(element, '.edit'));
element._messageText = 'good news, everyone!';
- flush();
+ await flush();
element.disabled = true;
tap(queryAndAssert(element, '.save'));
@@ -1138,14 +1172,16 @@
assert.isTrue(saveStub.calledOnce);
});
- test('proper event fires on resolve, comment is not saved', done => {
+ test('proper event fires on resolve, comment is not saved', async () => {
const save = sinon.stub(element, 'save');
+ const promise = mockPromise();
element.addEventListener('comment-update', e => {
assert.isTrue(e.detail.comment.unresolved);
assert.isFalse(save.called);
- done();
+ promise.resolve();
});
tap(queryAndAssert(element, '.resolve input'));
+ await promise;
});
test('resolved comment state indicated by checkbox', () => {
@@ -1209,7 +1245,7 @@
});
});
- test('cancelling an unsaved draft discards, persists in storage', () => {
+ test('cancelling an unsaved draft discards, persists in storage', async () => {
const clock: SinonFakeTimers = sinon.useFakeTimers();
const tickAndFlush = async (repetitions: number) => {
for (let i = 1; i <= repetitions; i++) {
@@ -1230,7 +1266,7 @@
...new Event('click'),
preventDefault: sinon.stub(),
});
- flush();
+ await flush();
assert.isTrue(discardSpy.called);
assert.isFalse(eraseStub.called);
});
@@ -1261,19 +1297,21 @@
assert.isTrue(discardStub.called);
});
- test('_handleFix fires create-fix event', done => {
+ test('_handleFix fires create-fix event', async () => {
+ const promise = mockPromise();
element.addEventListener(
'create-fix-comment',
(e: CreateFixCommentEvent) => {
assert.deepEqual(e.detail, element._getEventPayload());
- done();
+ promise.resolve();
}
);
element.isRobotComment = true;
element.comments = [element.comment!];
- flush();
+ await flush();
tap(queryAndAssert(element, '.fix'));
+ await promise;
});
test('do not show Please Fix button if human reply exists', () => {
@@ -1419,19 +1457,21 @@
queryAndAssert(element, '.robotActions gr-button');
});
- test('_handleShowFix fires open-fix-preview event', done => {
+ test('_handleShowFix fires open-fix-preview event', async () => {
+ const promise = mockPromise();
element.addEventListener('open-fix-preview', e => {
assert.deepEqual(e.detail, element._getEventPayload());
- done();
+ promise.resolve();
});
element.comment = {
...createComment(),
fix_suggestions: [{...createFixSuggestionInfo()}],
};
element.isRobotComment = true;
- flush();
+ await flush();
tap(queryAndAssert(element, '.show-fix'));
+ await promise;
});
});
@@ -1449,7 +1489,7 @@
sinon.restore();
});
- test('show tip when no cached record', done => {
+ test('show tip when no cached record', async () => {
element = draftFixture.instantiate() as GrComment;
const respectfulGetStub = stubStorage('getRespectfulTipVisibility');
const respectfulSetStub = stubStorage('setRespectfulTipVisibility');
@@ -1457,15 +1497,13 @@
// fake random
element.getRandomNum = () => 0;
element.comment = {__editing: true, __draft: true};
- flush(() => {
- assert.isTrue(respectfulGetStub.called);
- assert.isTrue(respectfulSetStub.called);
- assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
- done();
- });
+ await flush();
+ assert.isTrue(respectfulGetStub.called);
+ assert.isTrue(respectfulSetStub.called);
+ assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
});
- test('add 14-day delays once dismissed', done => {
+ test('add 14-day delays once dismissed', async () => {
element = draftFixture.instantiate() as GrComment;
const respectfulGetStub = stubStorage('getRespectfulTipVisibility');
const respectfulSetStub = stubStorage('setRespectfulTipVisibility');
@@ -1473,20 +1511,18 @@
// fake random
element.getRandomNum = () => 0;
element.comment = {__editing: true, __draft: true};
- flush(() => {
- assert.isTrue(respectfulGetStub.called);
- assert.isTrue(respectfulSetStub.called);
- assert.isTrue(respectfulSetStub.lastCall.args[0] === undefined);
- assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
+ await flush();
+ assert.isTrue(respectfulGetStub.called);
+ assert.isTrue(respectfulSetStub.called);
+ assert.isTrue(respectfulSetStub.lastCall.args[0] === undefined);
+ assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
- tap(queryAndAssert(element, '.respectfulReviewTip .close'));
- flush();
- assert.isTrue(respectfulSetStub.lastCall.args[0] === 14);
- done();
- });
+ tap(queryAndAssert(element, '.respectfulReviewTip .close'));
+ flush();
+ assert.isTrue(respectfulSetStub.lastCall.args[0] === 14);
});
- test('do not show tip when fall out of probability', done => {
+ test('do not show tip when fall out of probability', async () => {
element = draftFixture.instantiate() as GrComment;
const respectfulGetStub = stubStorage('getRespectfulTipVisibility');
const respectfulSetStub = stubStorage('setRespectfulTipVisibility');
@@ -1494,15 +1530,13 @@
// fake random
element.getRandomNum = () => 3;
element.comment = {__editing: true, __draft: true};
- flush(() => {
- assert.isTrue(respectfulGetStub.called);
- assert.isFalse(respectfulSetStub.called);
- assert.isNotOk(query(element, '.respectfulReviewTip'));
- done();
- });
+ await flush();
+ assert.isTrue(respectfulGetStub.called);
+ assert.isFalse(respectfulSetStub.called);
+ assert.isNotOk(query(element, '.respectfulReviewTip'));
});
- test('show tip when editing changed to true', done => {
+ test('show tip when editing changed to true', async () => {
element = draftFixture.instantiate() as GrComment;
const respectfulGetStub = stubStorage('getRespectfulTipVisibility');
const respectfulSetStub = stubStorage('setRespectfulTipVisibility');
@@ -1510,22 +1544,19 @@
// fake random
element.getRandomNum = () => 0;
element.comment = {__editing: false};
- flush(() => {
- assert.isFalse(respectfulGetStub.called);
- assert.isFalse(respectfulSetStub.called);
- assert.isNotOk(query(element, '.respectfulReviewTip'));
+ await flush();
+ assert.isFalse(respectfulGetStub.called);
+ assert.isFalse(respectfulSetStub.called);
+ assert.isNotOk(query(element, '.respectfulReviewTip'));
- element.editing = true;
- flush(() => {
- assert.isTrue(respectfulGetStub.called);
- assert.isTrue(respectfulSetStub.called);
- assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
- done();
- });
- });
+ element.editing = true;
+ await flush();
+ assert.isTrue(respectfulGetStub.called);
+ assert.isTrue(respectfulSetStub.called);
+ assert.isTrue(!!queryAndAssert(element, '.respectfulReviewTip'));
});
- test('no tip when cached record', done => {
+ test('no tip when cached record', async () => {
element = draftFixture.instantiate() as GrComment;
const respectfulGetStub = stubStorage('getRespectfulTipVisibility');
const respectfulSetStub = stubStorage('setRespectfulTipVisibility');
@@ -1533,12 +1564,10 @@
// fake random
element.getRandomNum = () => 0;
element.comment = {__editing: true, __draft: true};
- flush(() => {
- assert.isTrue(respectfulGetStub.called);
- assert.isFalse(respectfulSetStub.called);
- assert.isNotOk(query(element, '.respectfulReviewTip'));
- done();
- });
+ await flush();
+ assert.isTrue(respectfulGetStub.called);
+ assert.isFalse(respectfulSetStub.called);
+ assert.isNotOk(query(element, '.respectfulReviewTip'));
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
index b85703a..0cd522a 100644
--- a/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-copy-clipboard/gr-copy-clipboard.ts
@@ -19,10 +19,10 @@
import '../gr-icons/gr-icons';
import {IronIconElement} from '@polymer/iron-icon';
import {assertIsDefined, queryAndAssert} from '../../../utils/common-util';
-import {classMap} from 'lit-html/directives/class-map';
-import {ifDefined} from 'lit-html/directives/if-defined';
-import {css, customElement, html, property} from 'lit-element';
-import {GrLitElement} from '../../lit/gr-lit-element';
+import {classMap} from 'lit/directives/class-map';
+import {ifDefined} from 'lit/directives/if-defined';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {GrButton} from '../gr-button/gr-button';
const COPY_TIMEOUT_MS = 1000;
@@ -33,7 +33,7 @@
}
}
@customElement('gr-copy-clipboard')
-export class GrCopyClipboard extends GrLitElement {
+export class GrCopyClipboard extends LitElement {
@property({type: String})
text: string | undefined;
@@ -89,6 +89,7 @@
override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
iron-icon {
@@ -109,7 +110,7 @@
type="text"
@click="${this._handleInputClick}"
readonly=""
- bind-value=${this.text}
+ bind-value=${this.text || ''}
>
<input
id="input"
@@ -118,21 +119,24 @@
type="text"
@click="${this._handleInputClick}"
readonly=""
- .value=${this.text}
+ .value=${this.text || ''}
part="text-container-style"
/>
</iron-input>
- <gr-button
- id="copy-clipboard-button"
- link=""
+ <gr-tooltip-content
?has-tooltip=${this.hasTooltip}
- class="copyToClipboard"
title="${ifDefined(this.buttonTitle)}"
- @click="${this._copyToClipboard}"
- aria-label="Click to copy to clipboard"
>
- <iron-icon id="icon" icon="gr-icons:content-copy"></iron-icon>
- </gr-button>
+ <gr-button
+ id="copy-clipboard-button"
+ link=""
+ class="copyToClipboard"
+ @click="${this._copyToClipboard}"
+ aria-label="Click to copy to clipboard"
+ >
+ <iron-icon id="icon" icon="gr-icons:content-copy"></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>
</div> `;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
index 39ec9e4..99f9265 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
@@ -14,11 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import '../../../styles/shared-styles';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-date-formatter_html';
-import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
-import {property, customElement} from '@polymer/decorators';
+import '../gr-tooltip-content/gr-tooltip-content';
+import {css, html, LitElement} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {
parseDate,
fromNow,
@@ -76,13 +74,9 @@
}
@customElement('gr-date-formatter')
-export class GrDateFormatter extends TooltipMixin(PolymerElement) {
- static get template() {
- return htmlTemplate;
- }
-
- @property({type: String, notify: true})
- dateStr: string | null = null;
+export class GrDateFormatter extends LitElement {
+ @property({type: String})
+ dateStr: string | undefined = undefined;
@property({type: Boolean})
showDateAndTime = false;
@@ -92,30 +86,20 @@
* native browser tooltip.
*/
@property({type: Boolean})
- override hasTooltip = false;
+ withTooltip = false;
@property({type: Boolean})
showYesterday = false;
- /**
- * The title to be used as the native tooltip or by the tooltip behavior.
- */
- @property({
- type: String,
- reflectToAttribute: true,
- computed: '_computeFullDateStr(dateStr, _timeFormat, _dateFormat)',
- })
- override title = '';
-
/** @type {?{short: string, full: string}} */
@property({type: Object})
- _dateFormat?: DateFormatPair;
+ private dateFormat?: DateFormatPair;
@property({type: String})
- _timeFormat?: string;
+ private timeFormat?: string;
@property({type: Boolean})
- _relative = false;
+ private relative = false;
@property({type: Boolean})
forceRelative = false;
@@ -129,76 +113,110 @@
super();
}
+ static override get styles() {
+ return [
+ css`
+ host {
+ color: inherit;
+ display: inline;
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ if (!this.withTooltip) {
+ return this.renderDateString();
+ }
+
+ const fullDateStr = this.computeFullDateStr();
+ if (!fullDateStr) {
+ return this.renderDateString();
+ }
+ return html`
+ <gr-tooltip-content has-tooltip title=${fullDateStr}>
+ ${this.renderDateString()}
+ </gr-tooltip-content>
+ `;
+ }
+
+ private renderDateString() {
+ return html` <span>${this._computeDateStr()}</span>`;
+ }
+
override connectedCallback() {
super.connectedCallback();
this._loadPreferences();
}
+ // private but used by tests
_getUtcOffsetString() {
return utcOffsetString();
}
+ // private but used by tests
_loadPreferences() {
return this._getLoggedIn().then(loggedIn => {
if (!loggedIn) {
- this._timeFormat = TimeFormats.TIME_24;
- this._dateFormat = DateFormats.STD;
- this._relative = this.forceRelative;
+ this.timeFormat = TimeFormats.TIME_24;
+ this.dateFormat = DateFormats.STD;
+ this.relative = this.forceRelative;
return;
}
- return Promise.all([this._loadTimeFormat(), this._loadRelative()]);
+ return Promise.all([this._loadTimeFormat(), this.loadRelative()]);
});
}
+ // private but used in gr/file-list_test.js
_loadTimeFormat() {
- return this._getPreferences().then(preferences => {
+ return this.getPreferences().then(preferences => {
if (!preferences) {
throw Error('Preferences is not set');
}
- this._decideTimeFormat(preferences.time_format);
- this._decideDateFormat(preferences.date_format);
+ this.decideTimeFormat(preferences.time_format);
+ this.decideDateFormat(preferences.date_format);
});
}
- _decideTimeFormat(timeFormat: TimeFormat) {
+ private decideTimeFormat(timeFormat: TimeFormat) {
switch (timeFormat) {
case TimeFormat.HHMM_12:
- this._timeFormat = TimeFormats.TIME_12;
+ this.timeFormat = TimeFormats.TIME_12;
break;
case TimeFormat.HHMM_24:
- this._timeFormat = TimeFormats.TIME_24;
+ this.timeFormat = TimeFormats.TIME_24;
break;
default:
assertNever(timeFormat, `Invalid time format: ${timeFormat}`);
}
}
- _decideDateFormat(dateFormat: DateFormat) {
+ private decideDateFormat(dateFormat: DateFormat) {
switch (dateFormat) {
case DateFormat.STD:
- this._dateFormat = DateFormats.STD;
+ this.dateFormat = DateFormats.STD;
break;
case DateFormat.US:
- this._dateFormat = DateFormats.US;
+ this.dateFormat = DateFormats.US;
break;
case DateFormat.ISO:
- this._dateFormat = DateFormats.ISO;
+ this.dateFormat = DateFormats.ISO;
break;
case DateFormat.EURO:
- this._dateFormat = DateFormats.EURO;
+ this.dateFormat = DateFormats.EURO;
break;
case DateFormat.UK:
- this._dateFormat = DateFormats.UK;
+ this.dateFormat = DateFormats.UK;
break;
default:
assertNever(dateFormat, `Invalid date format: ${dateFormat}`);
}
}
- _loadRelative() {
- return this._getPreferences().then(prefs => {
+ private loadRelative() {
+ return this.getPreferences().then(prefs => {
// prefs.relative_date_in_change_table is not set when false.
- this._relative =
+ this.relative =
this.forceRelative || !!(prefs && prefs.relative_date_in_change_table);
});
}
@@ -207,70 +225,60 @@
return this.restApiService.getLoggedIn();
}
- _getPreferences() {
+ private getPreferences() {
return this.restApiService.getPreferences();
}
- _computeDateStr(
- dateStr?: Timestamp,
- timeFormat?: string,
- dateFormat?: DateFormatPair,
- relative?: boolean,
- showDateAndTime?: boolean,
- showYesterday?: boolean
- ) {
- if (!dateStr || !timeFormat || !dateFormat) {
+ // private but used by tests
+ _computeDateStr() {
+ if (!this.dateStr || !this.timeFormat || !this.dateFormat) {
return '';
}
- const date = parseDate(dateStr);
+ const date = parseDate(this.dateStr as Timestamp);
if (!isValidDate(date)) {
return '';
}
- if (relative) {
+ if (this.relative) {
return fromNow(date, this.relativeOptionNoAgo);
}
const now = new Date();
- let format = dateFormat.full;
+ let format = this.dateFormat.full;
if (isWithinDay(now, date)) {
- format = timeFormat;
- } else if (showYesterday && wasYesterday(now, date)) {
- return `Yesterday at ${formatDate(date, timeFormat)}`;
+ format = this.timeFormat;
+ } else if (this.showYesterday && wasYesterday(now, date)) {
+ return `Yesterday at ${formatDate(date, this.timeFormat)}`;
} else {
if (isWithinHalfYear(now, date)) {
- format = dateFormat.short;
+ format = this.dateFormat.short;
}
- if (this.showDateAndTime || showDateAndTime) {
- format = `${format} ${timeFormat}`;
+ if (this.showDateAndTime || this.showDateAndTime) {
+ format = `${format} ${this.timeFormat}`;
}
}
return formatDate(date, format);
}
- _timeToSecondsFormat(timeFormat: string | undefined) {
- return timeFormat === TimeFormats.TIME_12
- ? TimeFormats.TIME_12_WITH_SEC
- : TimeFormats.TIME_24_WITH_SEC;
- }
-
- _computeFullDateStr(
- dateStr?: Timestamp,
- timeFormat?: string,
- dateFormat?: DateFormatPair
- ) {
+ private computeFullDateStr() {
// Polymer 2: check for undefined
- if ([dateStr, timeFormat].includes(undefined) || !dateFormat) {
+ if (
+ [this.dateStr, this.timeFormat].includes(undefined) ||
+ !this.dateFormat
+ ) {
return undefined;
}
- if (!dateStr) {
+ if (!this.dateStr) {
return '';
}
- const date = parseDate(dateStr);
+ const date = parseDate(this.dateStr as Timestamp);
if (!isValidDate(date)) {
return '';
}
- let format = dateFormat.full + ', ';
- format += this._timeToSecondsFormat(timeFormat);
+ let format = this.dateFormat.full + ', ';
+ format +=
+ this.timeFormat === TimeFormats.TIME_12
+ ? TimeFormats.TIME_12_WITH_SEC
+ : TimeFormats.TIME_24_WITH_SEC;
return formatDate(date, format) + this._getUtcOffsetString();
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.js
index 9a96c2d..860a7e7 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.js
@@ -22,14 +22,18 @@
import {stubRestApi} from '../../../test/test-utils.js';
const basicFixture = fixtureFromTemplate(html`
-<gr-date-formatter date-str="2015-09-24 23:30:17.033000000"></gr-date-formatter>
+<gr-date-formatter withTooltip dateStr="2015-09-24 23:30:17.033000000">
+</gr-date-formatter>
+`);
+
+const lightFixture = fixtureFromTemplate(html`
+<gr-date-formatter dateStr="2015-09-24 23:30:17.033000000"></gr-date-formatter>
`);
suite('gr-date-formatter tests', () => {
let element;
setup(() => {
-
});
/**
@@ -41,7 +45,7 @@
return d;
}
- function testDates(nowStr, dateStr, expected, expectedWithDateAndTime,
+ async function testDates(nowStr, dateStr, expected, expectedWithDateAndTime,
expectedTooltip) {
// Normalize and convert the date to mimic server response.
dateStr = normalizedDate(dateStr)
@@ -50,13 +54,13 @@
.slice(0, -1);
sinon.useFakeTimers(normalizedDate(nowStr).getTime());
element.dateStr = dateStr;
- flush();
- const span = element.shadowRoot
- .querySelector('span');
+ await element.updateComplete;
+ const span = element.shadowRoot.querySelector('span');
+ const tooltip = element.shadowRoot.querySelector('gr-tooltip-content');
assert.equal(span.textContent.trim(), expected);
- assert.equal(element.title, expectedTooltip);
+ assert.equal(tooltip.title, expectedTooltip);
element.showDateAndTime = true;
- flush();
+ await element.updateComplete;
assert.equal(span.textContent.trim(), expectedWithDateAndTime);
}
@@ -81,35 +85,37 @@
test('invalid dates are quietly rejected', () => {
assert.notOk((new Date('foo')).valueOf());
- assert.equal(element._computeDateStr('foo', 'h:mm A'), '');
+ element.dateStr = 'foo';
+ element.timeFormat = 'h:mm A';
+ assert.equal(element._computeDateStr(), '');
});
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'15:34',
'15:34',
'Jul 29, 2015, 15:34:14');
});
- test('Within 24 hours on different days', () => {
- testDates('2015-07-29 03:34:14.985000000',
+ test('Within 24 hours on different days', async () => {
+ await testDates('2015-07-29 03:34:14.985000000',
'2015-07-28 20:25:14.985000000',
'Jul 28',
'Jul 28 20:25',
'Jul 28, 2015, 20:25:14');
});
- test('More than 24 hours but less than six months', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('More than 24 hours but less than six months', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-06-15 03:25:14.985000000',
'Jun 15',
'Jun 15 03:25',
'Jun 15, 2015, 03:25:14');
});
- test('More than six months', () => {
- testDates('2015-09-15 20:34:00.000000000',
+ test('More than six months', async () => {
+ await testDates('2015-09-15 20:34:00.000000000',
'2015-01-15 03:25:00.000000000',
'Jan 15, 2015',
'Jan 15, 2015 03:25',
@@ -128,24 +134,24 @@
return element._loadPreferences();
}));
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'15:34',
'15:34',
'07/29/15, 15:34:14');
});
- test('Within 24 hours on different days', () => {
- testDates('2015-07-29 03:34:14.985000000',
+ test('Within 24 hours on different days', async () => {
+ await testDates('2015-07-29 03:34:14.985000000',
'2015-07-28 20:25:14.985000000',
'07/28',
'07/28 20:25',
'07/28/15, 20:25:14');
});
- test('More than 24 hours but less than six months', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('More than 24 hours but less than six months', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-06-15 03:25:14.985000000',
'06/15',
'06/15 03:25',
@@ -164,24 +170,24 @@
return element._loadPreferences();
}));
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'15:34',
'15:34',
'2015-07-29, 15:34:14');
});
- test('Within 24 hours on different days', () => {
- testDates('2015-07-29 03:34:14.985000000',
+ test('Within 24 hours on different days', async () => {
+ await testDates('2015-07-29 03:34:14.985000000',
'2015-07-28 20:25:14.985000000',
'07-28',
'07-28 20:25',
'2015-07-28, 20:25:14');
});
- test('More than 24 hours but less than six months', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('More than 24 hours but less than six months', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-06-15 03:25:14.985000000',
'06-15',
'06-15 03:25',
@@ -200,24 +206,24 @@
return element._loadPreferences();
}));
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'15:34',
'15:34',
'29.07.2015, 15:34:14');
});
- test('Within 24 hours on different days', () => {
- testDates('2015-07-29 03:34:14.985000000',
+ test('Within 24 hours on different days', async () => {
+ await testDates('2015-07-29 03:34:14.985000000',
'2015-07-28 20:25:14.985000000',
'28. Jul',
'28. Jul 20:25',
'28.07.2015, 20:25:14');
});
- test('More than 24 hours but less than six months', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('More than 24 hours but less than six months', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-06-15 03:25:14.985000000',
'15. Jun',
'15. Jun 03:25',
@@ -236,24 +242,24 @@
return element._loadPreferences();
}));
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'15:34',
'15:34',
'29/07/2015, 15:34:14');
});
- test('Within 24 hours on different days', () => {
- testDates('2015-07-29 03:34:14.985000000',
+ test('Within 24 hours on different days', async () => {
+ await testDates('2015-07-29 03:34:14.985000000',
'2015-07-28 20:25:14.985000000',
'28/07',
'28/07 20:25',
'28/07/2015, 20:25:14');
});
- test('More than 24 hours but less than six months', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('More than 24 hours but less than six months', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-06-15 03:25:14.985000000',
'15/06',
'15/06 03:25',
@@ -273,8 +279,8 @@
})
);
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'3:34 PM',
'3:34 PM',
@@ -294,8 +300,8 @@
})
);
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'3:34 PM',
'3:34 PM',
@@ -315,8 +321,8 @@
})
);
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'3:34 PM',
'3:34 PM',
@@ -336,8 +342,8 @@
})
);
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'3:34 PM',
'3:34 PM',
@@ -357,8 +363,8 @@
})
);
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'3:34 PM',
'3:34 PM',
@@ -377,16 +383,16 @@
return element._loadPreferences();
}));
- test('Within 24 hours on same day', () => {
- testDates('2015-07-29 20:34:14.985000000',
+ test('Within 24 hours on same day', async () => {
+ await testDates('2015-07-29 20:34:14.985000000',
'2015-07-29 15:34:14.985000000',
'5 hours ago',
'5 hours ago',
'Jul 29, 2015, 3:34:14 PM');
});
- test('More than six months', () => {
- testDates('2015-09-15 20:34:00.000000000',
+ test('More than six months', async () => {
+ await testDates('2015-09-15 20:34:00.000000000',
'2015-01-15 03:25:00.000000000',
'8 months ago',
'8 months ago',
@@ -405,10 +411,10 @@
}));
test('Preferences are respected', () => {
- assert.equal(element._timeFormat, 'h:mm A');
- assert.equal(element._dateFormat.short, 'MM/DD');
- assert.equal(element._dateFormat.full, 'MM/DD/YY');
- assert.isTrue(element._relative);
+ assert.equal(element.timeFormat, 'h:mm A');
+ assert.equal(element.dateFormat.short, 'MM/DD');
+ assert.equal(element.dateFormat.full, 'MM/DD/YY');
+ assert.isTrue(element.relative);
});
});
@@ -419,10 +425,38 @@
}));
test('Default preferences are respected', () => {
- assert.equal(element._timeFormat, 'HH:mm');
- assert.equal(element._dateFormat.short, 'MMM DD');
- assert.equal(element._dateFormat.full, 'MMM DD, YYYY');
- assert.isFalse(element._relative);
+ assert.equal(element.timeFormat, 'HH:mm');
+ assert.equal(element.dateFormat.short, 'MMM DD');
+ assert.equal(element.dateFormat.full, 'MMM DD, YYYY');
+ assert.isFalse(element.relative);
+ });
+ });
+
+ suite('with tooltip', () => {
+ setup(async () => {
+ await stubRestAPI(null);
+ element = basicFixture.instantiate();
+ await element._loadPreferences();
+ await element.updateComplete;
+ });
+
+ test('Tooltip is present', () => {
+ const tooltip = element.shadowRoot.querySelector('gr-tooltip-content');
+ assert.isOk(tooltip);
+ });
+ });
+
+ suite('without tooltip', () => {
+ setup(async () => {
+ await stubRestAPI(null);
+ element = lightFixture.instantiate();
+ await element._loadPreferences();
+ await element.updateComplete;
+ });
+
+ test('Tooltip is absent', () => {
+ const tooltip = element.shadowRoot.querySelector('gr-tooltip-content');
+ assert.isNotOk(tooltip);
});
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
index f39e5b8..27c6341 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog.ts
@@ -15,6 +15,7 @@
* limitations under the License.
*/
import '../gr-button/gr-button';
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-dialog_html';
diff --git a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
index f8ddcfd..a5cf8f1 100644
--- a/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dialog/gr-dialog_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="shared-styles">
:host {
color: var(--primary-text-color);
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_html.ts b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_html.ts
index 18a46a0..9ec1d39 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list_html.ts
@@ -123,6 +123,7 @@
class="dropdown-trigger"
on-click="_showDropdownTapHandler"
slot="dropdown-trigger"
+ no-uppercase
>
<span id="triggerText">[[text]]</span>
<gr-copy-clipboard
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
index 078e2ac..f4179f4 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.ts
@@ -67,8 +67,11 @@
bold?: boolean;
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-dropdown')
-export class GrDropdown extends KeyboardShortcutMixin(PolymerElement) {
+export class GrDropdown extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
index b2bd925..bd1046f 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.ts
@@ -48,8 +48,11 @@
};
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-editable-label')
-export class GrEditableLabel extends KeyboardShortcutMixin(PolymerElement) {
+export class GrEditableLabel extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
index ac14960..3f759b5 100644
--- a/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-file-status-chip/gr-file-status-chip.ts
@@ -18,8 +18,8 @@
import {NormalizedFileInfo} from '../../change/gr-file-list/gr-file-list';
import {hasOwnProperty} from '../../../utils/common-util';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
const FileStatus = {
A: 'Added',
@@ -32,11 +32,11 @@
};
@customElement('gr-file-status-chip')
-export class GrFileStatusChip extends GrLitElement {
+export class GrFileStatusChip extends LitElement {
@property({type: Object})
file?: NormalizedFileInfo;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -65,7 +65,7 @@
];
}
- render() {
+ override render() {
return html` <span
class="${this._computeStatusClass(this.file)}"
tabindex="0"
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index 487f288..17621c3 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -16,17 +16,23 @@
*/
import '../gr-linked-text/gr-linked-text';
import {CommentLinks} from '../../../types/common';
-import {appContext} from '../../../services/app-context';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html, TemplateResult} from 'lit';
+import {customElement, property} from 'lit/decorators';
const CODE_MARKER_PATTERN = /^(`{1,3})([^`]+?)\1$/;
-export interface Block {
- type: string;
- text?: string;
- blocks?: Block[];
- items?: string[];
+export type Block = ListBlock | QuoteBlock | TextBlock;
+export interface ListBlock {
+ type: 'list';
+ items: string[];
+}
+export interface QuoteBlock {
+ type: 'quote';
+ blocks: Block[];
+}
+export interface TextBlock {
+ type: 'paragraph' | 'code' | 'pre';
+ text: string;
}
declare global {
@@ -35,7 +41,7 @@
}
}
@customElement('gr-formatted-text')
-export class GrFormattedText extends GrLitElement {
+export class GrFormattedText extends LitElement {
@property({type: String})
content?: string;
@@ -45,8 +51,6 @@
@property({type: Boolean, reflect: true})
noTrailingMargin = false;
- private readonly reporting = appContext.reportingService;
-
static override get styles() {
return [
css`
@@ -99,8 +103,9 @@
}
override render() {
- const nodes = this._computeNodes(this._computeBlocks(this.content));
- return html`<div id="container">${nodes}</div>`;
+ if (!this.content) return;
+ const blocks = this._computeBlocks(this.content);
+ return html`${blocks.map(block => this.renderBlock(block))}`;
}
/**
@@ -123,9 +128,7 @@
*
* NOTE: Strings appearing in all block objects are NOT escaped.
*/
- _computeBlocks(content?: string): Block[] {
- if (!content) return [];
-
+ _computeBlocks(content: string): Block[] {
const result: Block[] = [];
const lines = content.replace(/[\s\n\r\t]+$/g, '').split('\n');
@@ -134,82 +137,87 @@
continue;
}
- if (this._isCodeMarkLine(lines[i])) {
- // handle multi-line code
- let nextI = i + 1;
- while (!this._isCodeMarkLine(lines[nextI]) && nextI < lines.length) {
- nextI++;
- }
-
- if (this._isCodeMarkLine(lines[nextI])) {
+ if (this.isCodeMarkLine(lines[i])) {
+ const startOfCode = i + 1;
+ const endOfCode = this.getEndOfSection(
+ lines,
+ startOfCode,
+ line => !this.isCodeMarkLine(line)
+ );
+ // If the code extends to the end then there is no closing``` and the
+ // opening``` should not be counted as a multiline code block.
+ const lineAfterCode = lines[endOfCode];
+ if (lineAfterCode && this.isCodeMarkLine(lineAfterCode)) {
result.push({
type: 'code',
- text: lines.slice(i + 1, nextI).join('\n'),
+ // Does not include either of the ``` lines
+ text: lines.slice(startOfCode, endOfCode).join('\n'),
});
- i = nextI;
+ i = endOfCode; // advances past the closing```
continue;
}
-
- // otherwise treat it as regular line and continue
- // check for other cases
}
-
- if (this._isSingleLineCode(lines[i])) {
+ if (this.isSingleLineCode(lines[i])) {
// no guard check as _isSingleLineCode tested on the pattern
const codeContent = lines[i].match(CODE_MARKER_PATTERN)![2];
result.push({type: 'code', text: codeContent});
- } else if (this._isList(lines[i])) {
- let nextI = i + 1;
- while (this._isList(lines[nextI])) {
- nextI++;
- }
- result.push(this._makeList(lines.slice(i, nextI)));
- i = nextI - 1;
- } else if (this._isQuote(lines[i])) {
- let nextI = i + 1;
- while (this._isQuote(lines[nextI])) {
- nextI++;
- }
+ } else if (this.isList(lines[i])) {
+ const endOfList = this.getEndOfSection(lines, i + 1, line =>
+ this.isList(line)
+ );
+ result.push(this.makeList(lines.slice(i, endOfList)));
+ i = endOfList - 1;
+ } else if (this.isQuote(lines[i])) {
+ const endOfQuote = this.getEndOfSection(lines, i + 1, line =>
+ this.isQuote(line)
+ );
const blockLines = lines
- .slice(i, nextI)
+ .slice(i, endOfQuote)
.map(l => l.replace(/^[ ]?>[ ]?/, ''));
result.push({
type: 'quote',
blocks: this._computeBlocks(blockLines.join('\n')),
});
- i = nextI - 1;
- } else if (this._isPreFormat(lines[i])) {
- let nextI = i + 1;
+ i = endOfQuote - 1;
+ } else if (this.isPreFormat(lines[i])) {
// include pre or all regular lines but stop at next new line
- while (
- this._isPreFormat(lines[nextI]) ||
- (this._isRegularLine(lines[nextI]) &&
- !this._isWhitespaceLine(lines[nextI]) &&
- lines[nextI].length)
- ) {
- nextI++;
- }
+ const predicate = (line: string) =>
+ this.isPreFormat(line) ||
+ (this.isRegularLine(line) &&
+ !this.isWhitespaceLine(line) &&
+ line.length > 0);
+ const endOfPre = this.getEndOfSection(lines, i + 1, predicate);
result.push({
type: 'pre',
- text: lines.slice(i, nextI).join('\n'),
+ text: lines.slice(i, endOfPre).join('\n'),
});
- i = nextI - 1;
+ i = endOfPre - 1;
} else {
- let nextI = i + 1;
- while (this._isRegularLine(lines[nextI])) {
- nextI++;
- }
+ const endOfRegularLines = this.getEndOfSection(lines, i + 1, line =>
+ this.isRegularLine(line)
+ );
result.push({
type: 'paragraph',
- text: lines.slice(i, nextI).join('\n'),
+ text: lines.slice(i, endOfRegularLines).join('\n'),
});
- i = nextI - 1;
+ i = endOfRegularLines - 1;
}
}
return result;
}
+ private getEndOfSection(
+ lines: string[],
+ startIndex: number,
+ sectionPredicate: (line: string) => boolean
+ ) {
+ const index = lines
+ .slice(startIndex)
+ .findIndex(line => !sectionPredicate(line));
+ return index === -1 ? lines.length : index + startIndex;
+ }
+
/**
* Take a block of comment text that contains a list, generate appropriate
* block objects and append them to the output list.
@@ -222,105 +230,78 @@
*
* @param lines The block containing the list.
*/
- _makeList(lines: string[]) {
- const items = [];
- for (let i = 0; i < lines.length; i++) {
- let line = lines[i];
- line = line.substring(1).trim();
- items.push(line);
- }
+ private makeList(lines: string[]): Block {
+ const items = lines.map(line => line.substring(1).trim());
return {type: 'list', items};
}
- _isRegularLine(line: string) {
- // line can not be recognized by existing patterns
- if (line === undefined) return false;
+ private isRegularLine(line: string): boolean {
return (
- !this._isQuote(line) &&
- !this._isCodeMarkLine(line) &&
- !this._isSingleLineCode(line) &&
- !this._isList(line) &&
- !this._isPreFormat(line)
+ !this.isQuote(line) &&
+ !this.isCodeMarkLine(line) &&
+ !this.isSingleLineCode(line) &&
+ !this.isList(line) &&
+ !this.isPreFormat(line)
);
}
- _isQuote(line: string) {
- return line && (line.startsWith('> ') || line.startsWith(' > '));
+ private isQuote(line: string): boolean {
+ return line.startsWith('> ') || line.startsWith(' > ');
}
- _isCodeMarkLine(line: string) {
- return line && line.trim() === '```';
+ private isCodeMarkLine(line: string): boolean {
+ return line.trim() === '```';
}
- _isSingleLineCode(line: string) {
- return line && CODE_MARKER_PATTERN.test(line);
+ private isSingleLineCode(line: string): boolean {
+ return CODE_MARKER_PATTERN.test(line);
}
- _isPreFormat(line: string) {
- return line && /^[ \t]/.test(line) && !this._isWhitespaceLine(line);
+ private isPreFormat(line: string): boolean {
+ return /^[ \t]/.test(line) && !this.isWhitespaceLine(line);
}
- _isList(line: string) {
- return line && /^[-*] /.test(line);
+ private isList(line: string): boolean {
+ return /^[-*] /.test(line);
}
- _isWhitespaceLine(line: string) {
- return line && /^\s+$/.test(line);
+ private isWhitespaceLine(line: string): boolean {
+ return /^\s+$/.test(line);
}
- _makeLinkedText(content = '', isPre?: boolean) {
- const text = document.createElement('gr-linked-text');
- text.config = this.config;
- text.content = content;
- text.pre = true;
- if (isPre) {
- text.classList.add('pre');
+ private renderLinkedText(content: string, isPre?: boolean): TemplateResult {
+ return html`
+ <gr-linked-text
+ class="${isPre ? 'pre' : ''}"
+ .config=${this.config}
+ content=${content}
+ pre
+ ></gr-linked-text>
+ `;
+ }
+
+ private renderBlock(block: Block): TemplateResult {
+ switch (block.type) {
+ case 'paragraph':
+ return html`<p>${this.renderLinkedText(block.text)}</p>`;
+ case 'quote':
+ return html`
+ <blockquote>
+ ${block.blocks.map(subBlock => this.renderBlock(subBlock))}
+ </blockquote>
+ `;
+ case 'code':
+ return html`<code>${block.text}</code>`;
+ case 'pre':
+ return this.renderLinkedText(block.text, true);
+ case 'list':
+ return html`
+ <ul>
+ ${block.items.map(
+ item => html`<li>${this.renderLinkedText(item)}</li>`
+ )}
+ </ul>
+ `;
}
- return text;
- }
-
- /**
- * Map an array of block objects to an array of DOM nodes.
- */
- _computeNodes(blocks: Block[]): HTMLElement[] {
- return blocks.map(block => {
- if (block.type === 'paragraph') {
- const p = document.createElement('p');
- p.appendChild(this._makeLinkedText(block.text));
- return p;
- }
-
- if (block.type === 'quote') {
- const bq = document.createElement('blockquote');
- for (const node of this._computeNodes(block.blocks || [])) {
- if (node) bq.appendChild(node);
- }
- return bq;
- }
-
- if (block.type === 'code') {
- const code = document.createElement('code');
- code.textContent = block.text || '';
- return code;
- }
-
- if (block.type === 'pre') {
- return this._makeLinkedText(block.text, true);
- }
-
- if (block.type === 'list') {
- const ul = document.createElement('ul');
- const items = block.items || [];
- for (const item of items) {
- const li = document.createElement('li');
- li.appendChild(this._makeLinkedText(item));
- ul.appendChild(li);
- }
- return ul;
- }
-
- this.reporting.error(new Error(`Unrecognized block type: ${block.type}`));
- return document.createElement('span');
- });
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
index cf12032..8cecf71 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text_test.ts
@@ -17,40 +17,41 @@
import '../../../test/common-test-setup-karma';
import './gr-formatted-text';
-import {GrFormattedText, Block} from './gr-formatted-text';
+import {
+ GrFormattedText,
+ Block,
+ ListBlock,
+ TextBlock,
+ QuoteBlock,
+} from './gr-formatted-text';
const basicFixture = fixtureFromElement('gr-formatted-text');
suite('gr-formatted-text tests', () => {
let element: GrFormattedText;
- function assertBlock(
- result: Block[],
- index: number,
- type: string,
- text?: string
- ) {
- assert.equal(result[index].type, type);
- assert.equal(result[index].text, text);
+ function assertTextBlock(block: Block, type: string, text: string) {
+ assert.equal(block.type, type);
+ const textBlock = block as TextBlock;
+ assert.equal(textBlock.text, text);
}
- function assertListBlock(
- result: Block[],
- resultIndex: number,
- itemIndex: number,
- text: string
- ) {
- assert.equal(result[resultIndex].type, 'list');
- const item = result[resultIndex].items?.[itemIndex];
- assert.equal(item, text);
+ function assertListBlock(block: Block, items: string[]) {
+ assert.equal(block.type, 'list');
+ const listBlock = block as ListBlock;
+ assert.deepEqual(listBlock.items, items);
+ }
+
+ function assertQuoteBlock(block: Block): QuoteBlock {
+ assert.equal(block.type, 'quote');
+ return block as QuoteBlock;
}
setup(() => {
element = basicFixture.instantiate();
});
- test('parse null undefined and empty', () => {
- assert.lengthOf(element._computeBlocks(undefined), 0);
+ test('parse empty', () => {
assert.lengthOf(element._computeBlocks(''), 0);
});
@@ -58,53 +59,49 @@
const comment = 'Para1';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'paragraph', comment);
+ assertTextBlock(result[0], 'paragraph', comment);
});
test('parse multiline para', () => {
const comment = 'Para 1\nStill para 1';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'paragraph', comment);
+ assertTextBlock(result[0], 'paragraph', comment);
});
test('parse para break without special blocks', () => {
const comment = 'Para 1\n\nPara 2\n\nPara 3';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'paragraph', comment);
+ assertTextBlock(result[0], 'paragraph', comment);
});
test('parse quote', () => {
const comment = '> Quote text';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'quote');
- const blocks = result[0].blocks!;
- assert.lengthOf(blocks, 1);
- assertBlock(blocks, 0, 'paragraph', 'Quote text');
+ const quoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(quoteBlock.blocks[0], 'paragraph', 'Quote text');
});
test('parse quote lead space', () => {
const comment = ' > Quote text';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'quote');
- const blocks = result[0].blocks!;
- assert.lengthOf(blocks, 1);
- assertBlock(blocks, 0, 'paragraph', 'Quote text');
+ const quoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(quoteBlock.blocks[0], 'paragraph', 'Quote text');
});
test('parse multiline quote', () => {
const comment = '> Quote line 1\n> Quote line 2\n > Quote line 3\n';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'quote');
- const blocks = result[0].blocks!;
- assert.lengthOf(blocks, 1);
- assertBlock(
- blocks,
- 0,
+ const quoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(
+ quoteBlock.blocks[0],
'paragraph',
'Quote line 1\nQuote line 2\nQuote line 3'
);
@@ -114,49 +111,42 @@
const comment = ' Four space indent.';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'pre', comment);
+ assertTextBlock(result[0], 'pre', comment);
});
test('parse one space pre', () => {
const comment = ' One space indent.\n Another line.';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'pre', comment);
+ assertTextBlock(result[0], 'pre', comment);
});
test('parse tab pre', () => {
const comment = '\tOne tab indent.\n\tAnother line.\n Yet another!';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertBlock(result, 0, 'pre', comment);
+ assertTextBlock(result[0], 'pre', comment);
});
test('parse star list', () => {
const comment = '* Item 1\n* Item 2\n* Item 3';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertListBlock(result, 0, 0, 'Item 1');
- assertListBlock(result, 0, 1, 'Item 2');
- assertListBlock(result, 0, 2, 'Item 3');
+ assertListBlock(result[0], ['Item 1', 'Item 2', 'Item 3']);
});
test('parse dash list', () => {
const comment = '- Item 1\n- Item 2\n- Item 3';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertListBlock(result, 0, 0, 'Item 1');
- assertListBlock(result, 0, 1, 'Item 2');
- assertListBlock(result, 0, 2, 'Item 3');
+ assertListBlock(result[0], ['Item 1', 'Item 2', 'Item 3']);
});
test('parse mixed list', () => {
const comment = '- Item 1\n* Item 2\n- Item 3\n* Item 4';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assertListBlock(result, 0, 0, 'Item 1');
- assertListBlock(result, 0, 1, 'Item 2');
- assertListBlock(result, 0, 2, 'Item 3');
- assertListBlock(result, 0, 3, 'Item 4');
+ assertListBlock(result[0], ['Item 1', 'Item 2', 'Item 3', 'Item 4']);
});
test('parse mixed block types', () => {
@@ -176,64 +166,75 @@
'Parting words.';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 7);
- assertBlock(result, 0, 'paragraph', 'Paragraph\nacross\na\nfew\nlines.\n');
+ assertTextBlock(
+ result[0],
+ 'paragraph',
+ 'Paragraph\nacross\na\nfew\nlines.\n'
+ );
- assert.equal(result[1].type, 'quote');
- const secondBlocks = result[1].blocks!;
- assert.lengthOf(secondBlocks, 1);
- assertBlock(secondBlocks, 0, 'paragraph', 'Quote\nacross\nnot many lines.');
+ const quoteBlock = assertQuoteBlock(result[1]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(
+ quoteBlock.blocks[0],
+ 'paragraph',
+ 'Quote\nacross\nnot many lines.'
+ );
- assertBlock(result, 2, 'paragraph', 'Another paragraph\n');
- assertListBlock(result, 3, 0, 'Series');
- assertListBlock(result, 3, 1, 'of');
- assertListBlock(result, 3, 2, 'list');
- assertListBlock(result, 3, 3, 'items');
- assertBlock(result, 4, 'paragraph', 'Yet another paragraph\n');
- assertBlock(result, 5, 'pre', '\tPreformatted text.');
- assertBlock(result, 6, 'paragraph', 'Parting words.');
+ assertTextBlock(result[2], 'paragraph', 'Another paragraph\n');
+ assertListBlock(result[3], ['Series', 'of', 'list', 'items']);
+ assertTextBlock(result[4], 'paragraph', 'Yet another paragraph\n');
+ assertTextBlock(result[5], 'pre', '\tPreformatted text.');
+ assertTextBlock(result[6], 'paragraph', 'Parting words.');
});
test('bullet list 1', () => {
- const comment = 'A\n\n* line 1\n* 2nd line';
+ const comment = 'A\n\n* line 1';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'paragraph', 'A\n');
- assertListBlock(result, 1, 0, 'line 1');
- assertListBlock(result, 1, 1, '2nd line');
+ assertTextBlock(result[0], 'paragraph', 'A\n');
+ assertListBlock(result[1], ['line 1']);
});
test('bullet list 2', () => {
- const comment = 'A\n* line 1\n* 2nd line\n\nB';
+ const comment = 'A\n\n* line 1\n* 2nd line';
const result = element._computeBlocks(comment);
- assert.lengthOf(result, 3);
- assertBlock(result, 0, 'paragraph', 'A');
- assertListBlock(result, 1, 0, 'line 1');
- assertListBlock(result, 1, 1, '2nd line');
- assertBlock(result, 2, 'paragraph', 'B');
+ assert.lengthOf(result, 2);
+ assertTextBlock(result[0], 'paragraph', 'A\n');
+ assertListBlock(result[1], ['line 1', '2nd line']);
});
test('bullet list 3', () => {
- const comment = '* line 1\n* 2nd line\n\nB';
+ const comment = 'A\n* line 1\n* 2nd line\n\nB';
const result = element._computeBlocks(comment);
- assert.lengthOf(result, 2);
- assertListBlock(result, 0, 0, 'line 1');
- assertListBlock(result, 0, 1, '2nd line');
- assertBlock(result, 1, 'paragraph', 'B');
+ assert.lengthOf(result, 3);
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertListBlock(result[1], ['line 1', '2nd line']);
+ assertTextBlock(result[2], 'paragraph', 'B');
});
test('bullet list 4', () => {
+ const comment = '* line 1\n* 2nd line\n\nB';
+ const result = element._computeBlocks(comment);
+ assert.lengthOf(result, 2);
+ assertListBlock(result[0], ['line 1', '2nd line']);
+ assertTextBlock(result[1], 'paragraph', 'B');
+ });
+
+ test('bullet list 5', () => {
const comment =
'To see this bug, you have to:\n' +
'* Be on IMAP or EAS (not on POP)\n' +
'* Be very unlucky\n';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'paragraph', 'To see this bug, you have to:');
- assertListBlock(result, 1, 0, 'Be on IMAP or EAS (not on POP)');
- assertListBlock(result, 1, 1, 'Be very unlucky');
+ assertTextBlock(result[0], 'paragraph', 'To see this bug, you have to:');
+ assertListBlock(result[1], [
+ 'Be on IMAP or EAS (not on POP)',
+ 'Be very unlucky',
+ ]);
});
- test('bullet list 5', () => {
+ test('bullet list 6', () => {
const comment =
'To see this bug,\n' +
'you have to:\n' +
@@ -241,37 +242,36 @@
'* Be very unlucky\n';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'paragraph', 'To see this bug,\nyou have to:');
- assertListBlock(result, 1, 0, 'Be on IMAP or EAS (not on POP)');
- assertListBlock(result, 1, 1, 'Be very unlucky');
+ assertTextBlock(result[0], 'paragraph', 'To see this bug,\nyou have to:');
+ assertListBlock(result[1], [
+ 'Be on IMAP or EAS (not on POP)',
+ 'Be very unlucky',
+ ]);
});
test('dash list 1', () => {
const comment = 'A\n- line 1\n- 2nd line';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'paragraph', 'A');
- assertListBlock(result, 1, 0, 'line 1');
- assertListBlock(result, 1, 1, '2nd line');
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertListBlock(result[1], ['line 1', '2nd line']);
});
test('dash list 2', () => {
const comment = 'A\n- line 1\n- 2nd line\n\nB';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 3);
- assertBlock(result, 0, 'paragraph', 'A');
- assertListBlock(result, 1, 0, 'line 1');
- assertListBlock(result, 1, 1, '2nd line');
- assertBlock(result, 2, 'paragraph', 'B');
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertListBlock(result[1], ['line 1', '2nd line']);
+ assertTextBlock(result[2], 'paragraph', 'B');
});
test('dash list 3', () => {
const comment = '- line 1\n- 2nd line\n\nB';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertListBlock(result, 0, 0, 'line 1');
- assertListBlock(result, 0, 1, '2nd line');
- assertBlock(result, 1, 'paragraph', 'B');
+ assertListBlock(result[0], ['line 1', '2nd line']);
+ assertTextBlock(result[1], 'paragraph', 'B');
});
test('nested list will NOT be recognized', () => {
@@ -279,134 +279,143 @@
const comment = '- line 1\n - line with indentation\n- line 2';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 3);
- assertListBlock(result, 0, 0, 'line 1');
- assert.equal(result[1].type, 'pre');
- assertListBlock(result, 2, 0, 'line 2');
+ assertListBlock(result[0], ['line 1']);
+ assertTextBlock(result[1], 'pre', ' - line with indentation');
+ assertListBlock(result[2], ['line 2']);
});
test('pre format 1', () => {
const comment = 'A\n This is pre\n formatted';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'paragraph', 'A');
- assertBlock(result, 1, 'pre', ' This is pre\n formatted');
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertTextBlock(result[1], 'pre', ' This is pre\n formatted');
});
test('pre format 2', () => {
const comment = 'A\n This is pre\n formatted\n\nbut this is not';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 3);
- assertBlock(result, 0, 'paragraph', 'A');
- assertBlock(result, 1, 'pre', ' This is pre\n formatted');
- assertBlock(result, 2, 'paragraph', 'but this is not');
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertTextBlock(result[1], 'pre', ' This is pre\n formatted');
+ assertTextBlock(result[2], 'paragraph', 'but this is not');
});
test('pre format 3', () => {
const comment = 'A\n Q\n <R>\n S\n\nB';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 3);
- assertBlock(result, 0, 'paragraph', 'A');
- assertBlock(result, 1, 'pre', ' Q\n <R>\n S');
- assertBlock(result, 2, 'paragraph', 'B');
+ assertTextBlock(result[0], 'paragraph', 'A');
+ assertTextBlock(result[1], 'pre', ' Q\n <R>\n S');
+ assertTextBlock(result[2], 'paragraph', 'B');
});
test('pre format 4', () => {
const comment = ' Q\n <R>\n S\n\nB';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'pre', ' Q\n <R>\n S');
- assertBlock(result, 1, 'paragraph', 'B');
+ assertTextBlock(result[0], 'pre', ' Q\n <R>\n S');
+ assertTextBlock(result[1], 'paragraph', 'B');
});
test('pre format 5', () => {
const comment = ' Q\n <R>\n S\n \nB';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assertBlock(result, 0, 'pre', ' Q\n <R>\n S');
- assertBlock(result, 1, 'paragraph', ' \nB');
+ assertTextBlock(result[0], 'pre', ' Q\n <R>\n S');
+ assertTextBlock(result[1], 'paragraph', ' \nB');
});
test('quote 1', () => {
- const comment = "> I'm happy\n > with quotes!\n\nSee above.";
+ const comment = "> I'm happy with quotes!!";
const result = element._computeBlocks(comment);
- assert.lengthOf(result, 2);
- assert.equal(result[0].type, 'quote');
- const blocks = result[0].blocks!;
- assert.lengthOf(blocks, 1);
- assertBlock(blocks, 0, 'paragraph', "I'm happy\nwith quotes!");
- assertBlock(result, 1, 'paragraph', 'See above.');
+ assert.lengthOf(result, 1);
+ const quoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(
+ quoteBlock.blocks[0],
+ 'paragraph',
+ "I'm happy with quotes!!"
+ );
});
test('quote 2', () => {
+ const comment = "> I'm happy\n > with quotes!\n\nSee above.";
+ const result = element._computeBlocks(comment);
+ assert.lengthOf(result, 2);
+ const quoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(
+ quoteBlock.blocks[0],
+ 'paragraph',
+ "I'm happy\nwith quotes!"
+ );
+ assertTextBlock(result[1], 'paragraph', 'See above.');
+ });
+
+ test('quote 3', () => {
const comment = 'See this said:\n > a quoted\n > string block\n\nOK?';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 3);
- assertBlock(result, 0, 'paragraph', 'See this said:');
- assert.equal(result[1].type, 'quote');
- const secondBlocks = result[1].blocks!;
- assert.lengthOf(secondBlocks, 1);
- assertBlock(secondBlocks, 0, 'paragraph', 'a quoted\nstring block');
- assertBlock(result, 2, 'paragraph', 'OK?');
+ assertTextBlock(result[0], 'paragraph', 'See this said:');
+ const quoteBlock = assertQuoteBlock(result[1]);
+ assert.lengthOf(quoteBlock.blocks, 1);
+ assertTextBlock(
+ quoteBlock.blocks[0],
+ 'paragraph',
+ 'a quoted\nstring block'
+ );
+ assertTextBlock(result[2], 'paragraph', 'OK?');
});
test('nested quotes', () => {
const comment = ' > > prior\n > \n > next\n';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'quote');
- const blocks = result[0].blocks!;
- assert.lengthOf(blocks, 2);
- assert.equal(blocks[0].type, 'quote');
- const blocksBlocks = blocks[0].blocks!;
- assert.lengthOf(blocksBlocks, 1);
- assertBlock(blocksBlocks, 0, 'paragraph', 'prior');
- assertBlock(blocks, 1, 'paragraph', 'next');
+ const outerQuoteBlock = assertQuoteBlock(result[0]);
+ assert.lengthOf(outerQuoteBlock.blocks, 2);
+ const nestedQuoteBlock = assertQuoteBlock(outerQuoteBlock.blocks[0]);
+ assert.lengthOf(nestedQuoteBlock.blocks, 1);
+ assertTextBlock(nestedQuoteBlock.blocks[0], 'paragraph', 'prior');
+ assertTextBlock(outerQuoteBlock.blocks[1], 'paragraph', 'next');
});
test('code 1', () => {
const comment = '```\n// test code\n```';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'code');
- assert.equal(result[0].text, '// test code');
+ assertTextBlock(result[0], 'code', '// test code');
});
test('code 2', () => {
const comment = 'test code\n```// test code```';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assert.equal(result[0].type, 'paragraph');
- assert.equal(result[0].text, 'test code');
- assert.equal(result[1].type, 'code');
- assert.equal(result[1].text, '// test code');
+ assertTextBlock(result[0], 'paragraph', 'test code');
+ assertTextBlock(result[1], 'code', '// test code');
});
- test('code 3', () => {
- const comment = 'test code\n```// test code```';
- const result = element._computeBlocks(comment);
- assert.lengthOf(result, 2);
- assert.equal(result[0].type, 'paragraph');
- assert.equal(result[0].text, 'test code');
- assert.equal(result[1].type, 'code');
- assert.equal(result[1].text, '// test code');
- });
-
- test('not a code', () => {
+ test('not a code block', () => {
const comment = 'test code\n```// test code';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 1);
- assert.equal(result[0].type, 'paragraph');
- assert.equal(result[0].text, 'test code\n```// test code');
+ assertTextBlock(result[0], 'paragraph', 'test code\n```// test code');
});
- test('not a code 2', () => {
+ test('not a code block 2', () => {
const comment = 'test code\n```\n// test code';
const result = element._computeBlocks(comment);
assert.lengthOf(result, 2);
- assert.equal(result[0].type, 'paragraph');
- assert.equal(result[0].text, 'test code');
- assert.equal(result[1].type, 'paragraph');
- assert.equal(result[1].text, '```\n// test code');
+ assertTextBlock(result[0], 'paragraph', 'test code');
+ assertTextBlock(result[1], 'paragraph', '```\n// test code');
+ });
+
+ test('not a code block 3', () => {
+ const comment = 'test code\n```';
+ const result = element._computeBlocks(comment);
+ assert.lengthOf(result, 2);
+ assertTextBlock(result[0], 'paragraph', 'test code');
+ assertTextBlock(result[1], 'paragraph', '```');
});
test('mix all 1', () => {
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index a788f05..b789bee 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -16,10 +16,11 @@
*/
import '@polymer/iron-icon/iron-icon';
+import '../../../styles/gr-font-styles';
import '../../../styles/shared-styles';
import '../gr-avatar/gr-avatar';
import '../gr-button/gr-button';
-import {hovercardBehaviorMixin} from '../gr-hovercard/gr-hovercard-behavior';
+import {HovercardBehaviorMixin} from '../gr-hovercard/gr-hovercard-behavior';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard-account_html';
import {appContext} from '../../../services/app-context';
@@ -45,8 +46,11 @@
import {isInvolved, isRemovableReviewer} from '../../../utils/change-util';
import {assertIsDefined} from '../../../utils/common-util';
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = HovercardBehaviorMixin(PolymerElement);
+
@customElement('gr-hovercard-account')
-export class GrHovercardAccount extends hovercardBehaviorMixin(PolymerElement) {
+export class GrHovercardAccount extends base {
static get template() {
return htmlTemplate;
}
@@ -92,7 +96,7 @@
this.reporting = appContext.reportingService;
}
- connectedCallback() {
+ override connectedCallback() {
super.connectedCallback();
this.restApiService.getConfig().then(config => {
this._config = config;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
index dac5962..076553b 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
@@ -18,6 +18,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-hovercard-shared-style">
.top,
.attention,
@@ -125,7 +128,7 @@
<span class="value">[[_computeReason(change)]]</span>
<template is="dom-if" if="[[_computeLastUpdate(change)]]">
(<gr-date-formatter
- has-tooltip
+ withTooltip
date-str="[[_computeLastUpdate(change)]]"
></gr-date-formatter
>)
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
index e9a224c..82f64d0 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
@@ -109,7 +109,7 @@
stubRestApi('removeChangeReviewer').returns(Promise.resolve({ok: true}));
const reloadListener = sinon.spy();
element._target.addEventListener('reload', reloadListener);
- flush();
+ await flush();
const button = element.shadowRoot.querySelector('.removeReviewerOrCC');
assert.isOk(button);
assert.equal(button.innerText, 'Remove Reviewer');
@@ -132,7 +132,7 @@
const reloadListener = sinon.spy();
element._target.addEventListener('reload', reloadListener);
- flush();
+ await flush();
const button = element.shadowRoot.querySelector('.changeReviewerOrCC');
assert.isOk(button);
@@ -156,7 +156,7 @@
stubRestApi('removeChangeReviewer').returns(Promise.resolve({ok: true}));
const reloadListener = sinon.spy();
element._target.addEventListener('reload', reloadListener);
- flush();
+ await flush();
const button = element.shadowRoot.querySelector('.changeReviewerOrCC');
assert.isOk(button);
@@ -180,7 +180,7 @@
const reloadListener = sinon.spy();
element._target.addEventListener('reload', reloadListener);
- flush();
+ await flush();
const button = element.shadowRoot.querySelector('.removeReviewerOrCC');
assert.equal(button.innerText, 'Remove CC');
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
index 76c13e3..bbd1708 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard-behavior.ts
@@ -19,7 +19,6 @@
import {getRootElement} from '../../../scripts/rootElement';
import {Constructor} from '../../../utils/common-util';
import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
import {property, observe} from '@polymer/decorators';
import {
pushScrollLock,
@@ -82,401 +81,396 @@
* @polymer
* @mixinFunction
*/
-export const hovercardBehaviorMixin = dedupingMixin(
- <T extends Constructor<PolymerElement>>(
- superClass: T
- ): T & Constructor<GrHovercardBehaviorInterface> => {
+export const HovercardBehaviorMixin = <T extends Constructor<PolymerElement>>(
+ superClass: T
+) => {
+ /**
+ * @polymer
+ * @mixinClass
+ */
+ class Mixin extends superClass {
+ @property({type: Object})
+ _target: HTMLElement | null = null;
+
+ // Determines whether or not the hovercard is visible.
+ @property({type: Boolean})
+ _isShowing = false;
+
+ // The `id` of the element that the hovercard is anchored to.
+ @property({type: String})
+ for?: string;
+
/**
- * @polymer
- * @mixinClass
+ * The spacing between the top of the hovercard and the element it is
+ * anchored to.
*/
- class Mixin extends superClass {
- @property({type: Object})
- _target: HTMLElement | null = null;
+ @property({type: Number})
+ offset = 14;
- // Determines whether or not the hovercard is visible.
- @property({type: Boolean})
- _isShowing = false;
+ /**
+ * Positions the hovercard to the top, right, bottom, left, bottom-left,
+ * bottom-right, top-left, or top-right of its content.
+ */
+ @property({type: String})
+ position = 'right';
- // The `id` of the element that the hovercard is anchored to.
- @property({type: String})
- for?: string;
+ @property({type: Object})
+ container: HTMLElement | null = null;
- /**
- * The spacing between the top of the hovercard and the element it is
- * anchored to.
- */
- @property({type: Number})
- offset = 14;
+ private hideTask?: DelayedTask;
- /**
- * Positions the hovercard to the top, right, bottom, left, bottom-left,
- * bottom-right, top-left, or top-right of its content.
- */
- @property({type: String})
- position = 'right';
+ private showTask?: DelayedTask;
- @property({type: Object})
- container: HTMLElement | null = null;
+ private isScheduledToShow?: boolean;
- private hideTask?: DelayedTask;
+ private isScheduledToHide?: boolean;
- private showTask?: DelayedTask;
-
- private isScheduledToShow?: boolean;
-
- private isScheduledToHide?: boolean;
-
- override connectedCallback() {
- super.connectedCallback();
- if (!this._target) {
- this._target = this.target;
- }
- this._target.addEventListener('mouseenter', this.debounceShow);
- this._target.addEventListener('focus', this.debounceShow);
- this._target.addEventListener('mouseleave', this.debounceHide);
- this._target.addEventListener('blur', this.debounceHide);
-
- // when click, dismiss immediately
- this._target.addEventListener('click', this.hide);
-
- // show the hovercard if mouse moves to hovercard
- // this will cancel pending hide as well
- this.addEventListener('mouseenter', this.show);
- this.addEventListener('mouseenter', this.lock);
- // when leave hovercard, hide it immediately
- this.addEventListener('mouseleave', this.hide);
- this.addEventListener('mouseleave', this.unlock);
- }
-
- override disconnectedCallback() {
- this.cancelShowTask();
- this.cancelHideTask();
- this.unlock();
- super.disconnectedCallback();
- }
-
- override ready() {
- super.ready();
- // First, check to see if the container has already been created.
- this.container = getHovercardContainer({createIfNotExists: true});
- }
-
- removeListeners() {
- this._target?.removeEventListener('mouseenter', this.debounceShow);
- this._target?.removeEventListener('focus', this.debounceShow);
- this._target?.removeEventListener('mouseleave', this.debounceHide);
- this._target?.removeEventListener('blur', this.debounceHide);
- this._target?.removeEventListener('click', this.hide);
- }
-
- readonly debounceHide = () => {
- this.cancelShowTask();
- if (!this._isShowing || this.isScheduledToHide) return;
- this.isScheduledToHide = true;
- this.hideTask = debounce(
- this.hideTask,
- () => {
- // This happens when hide immediately through click or mouse leave
- // on the hovercard
- if (!this.isScheduledToHide) return;
- this.hide();
- },
- HIDE_DELAY_MS
- );
- };
-
- cancelHideTask() {
- if (this.hideTask) {
- this.hideTask.cancel();
- this.isScheduledToHide = false;
- }
- }
-
- /**
- * Hovercard elements are created outside of <gr-app>, so if you want to fire
- * events, then you probably want to do that through the target element.
- */
-
- dispatchEventThroughTarget(eventName: string): void;
-
- dispatchEventThroughTarget(
- eventName: 'show-alert',
- detail: ShowAlertEventDetail
- ): void;
-
- dispatchEventThroughTarget(
- eventName: 'reload',
- detail: ReloadEventDetail
- ): void;
-
- dispatchEventThroughTarget(eventName: string, detail?: unknown) {
- if (!detail) detail = {};
- if (this._target)
- this._target.dispatchEvent(
- new CustomEvent(eventName, {
- detail,
- bubbles: true,
- composed: true,
- })
- );
- }
-
- /**
- * Returns the target element that the hovercard is anchored to (the `id` of
- * the `for` property).
- */
- get target(): HTMLElement {
- const parentNode = this.parentNode;
- // If the parentNode is a document fragment, then we need to use the host.
- const ownerRoot = this.getRootNode() as ShadowRoot;
- let target;
- if (this.for) {
- target = ownerRoot.querySelector('#' + this.for);
- } else {
- target =
- !parentNode || parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
- ? ownerRoot.host
- : parentNode;
- }
- return target as HTMLElement;
- }
-
- /**
- * unlock scroll, this will resume the scroll outside of the hovercard.
- */
- readonly unlock = () => {
- removeScrollLock(this);
- };
-
- /**
- * Hides/closes the hovercard. This occurs when the user triggers the
- * `mouseleave` event on the hovercard's `target` element (as long as the
- * user is not hovering over the hovercard).
- *
- */
- readonly hide = (e?: MouseEvent) => {
- this.cancelHideTask();
- this.cancelShowTask();
- if (!this._isShowing) {
- return;
- }
-
- // If the user is now hovering over the hovercard or the user is returning
- // from the hovercard but now hovering over the target (to stop an annoying
- // flicker effect), just return.
- if (e) {
- if (
- e.relatedTarget === this ||
- (e.target === this && e.relatedTarget === this._target)
- ) {
- return;
- }
- }
-
- // Mark that the hovercard is not visible and do not allow focusing
- this._isShowing = false;
-
- // Clear styles in preparation for the next time we need to show the card
- this.classList.remove(HOVER_CLASS);
-
- // Reset and remove the hovercard from the DOM
- this.style.cssText = '';
- this.$['container'].setAttribute('tabindex', '-1');
-
- // Remove the hovercard from the container, given that it is still a child
- // of the container.
- if (this.container?.contains(this)) {
- this.container.removeChild(this);
- }
- };
-
- /**
- * Shows/opens the hovercard with a fixed delay.
- */
- readonly debounceShow = () => {
- this.debounceShowBy(SHOW_DELAY_MS);
- };
-
- /**
- * Shows/opens the hovercard with the given delay.
- */
- debounceShowBy(delayMs: number) {
- this.cancelHideTask();
- if (this._isShowing || this.isScheduledToShow) return;
- this.isScheduledToShow = true;
- this.showTask = debounce(
- this.showTask,
- () => {
- // This happens when the mouse leaves the target before the delay is over.
- if (!this.isScheduledToShow) return;
- this.show();
- },
- delayMs
- );
- }
-
- cancelShowTask() {
- if (this.showTask) {
- this.showTask.cancel();
- this.isScheduledToShow = false;
- }
- }
-
- /**
- * Lock background scroll but enable scroll inside of current hovercard.
- */
- readonly lock = () => {
- pushScrollLock(this);
- };
-
- /**
- * Shows/opens the hovercard. This occurs when the user triggers the
- * `mousenter` event on the hovercard's `target` element.
- */
- readonly show = () => {
- this.cancelHideTask();
- this.cancelShowTask();
- if (this._isShowing || !this.container) {
- return;
- }
-
- // Mark that the hovercard is now visible
- this._isShowing = true;
- this.setAttribute('tabindex', '0');
-
- // Add it to the DOM and calculate its position
- this.container.appendChild(this);
- // We temporarily hide the hovercard until we have found the correct
- // position for it.
- this.classList.add(HIDE_CLASS);
- this.classList.add(HOVER_CLASS);
- // Make sure that the hovercard actually rendered and all dom-if
- // statements processed, so that we can measure the (invisible)
- // hovercard properly in updatePosition().
- flush();
- this.updatePosition();
- this.classList.remove(HIDE_CLASS);
- };
-
- updatePosition() {
- const positionsToTry = new Set([
- this.position,
- 'right',
- 'bottom-right',
- 'top-right',
- 'bottom',
- 'top',
- 'bottom-left',
- 'top-left',
- 'left',
- ]);
- for (const position of positionsToTry) {
- this.updatePositionTo(position);
- if (this._isInsideViewport()) return;
- }
- console.warn('Could not find a visible position for the hovercard.');
- }
-
- _isInsideViewport() {
- const thisRect = this.getBoundingClientRect();
- if (thisRect.top < 0) return false;
- if (thisRect.left < 0) return false;
- const docuRect = document.documentElement.getBoundingClientRect();
- if (thisRect.bottom > docuRect.height) return false;
- if (thisRect.right > docuRect.width) return false;
- return true;
- }
-
- /**
- * Updates the hovercard's position based the current position of the `target`
- * element.
- *
- * The hovercard is supposed to stay open if the user hovers over it.
- * To keep it open when the user moves away from the target, the bounding
- * rects of the target and hovercard must touch or overlap.
- *
- * NOTE: You do not need to directly call this method unless you need to
- * update the position of the tooltip while it is already visible (the
- * target element has moved and the tooltip is still open).
- */
- updatePositionTo(position: string) {
- if (!this._target) {
- return;
- }
-
- // Make sure that thisRect will not get any paddings and such included
- // in the width and height of the bounding client rect.
- this.style.cssText = '';
-
- const docuRect = document.documentElement.getBoundingClientRect();
- const targetRect = this._target.getBoundingClientRect();
- const thisRect = this.getBoundingClientRect();
-
- const targetLeft = targetRect.left - docuRect.left;
- const targetTop = targetRect.top - docuRect.top;
-
- let hovercardLeft;
- let hovercardTop;
-
- switch (position) {
- case 'top':
- hovercardLeft =
- targetLeft + (targetRect.width - thisRect.width) / 2;
- hovercardTop = targetTop - thisRect.height - this.offset;
- break;
- case 'bottom':
- hovercardLeft =
- targetLeft + (targetRect.width - thisRect.width) / 2;
- hovercardTop = targetTop + targetRect.height + this.offset;
- break;
- case 'left':
- hovercardLeft = targetLeft - thisRect.width - this.offset;
- hovercardTop =
- targetTop + (targetRect.height - thisRect.height) / 2;
- break;
- case 'right':
- hovercardLeft = targetLeft + targetRect.width + this.offset;
- hovercardTop =
- targetTop + (targetRect.height - thisRect.height) / 2;
- break;
- case 'bottom-right':
- hovercardLeft = targetLeft + targetRect.width + this.offset;
- hovercardTop = targetTop;
- break;
- case 'bottom-left':
- hovercardLeft = targetLeft - thisRect.width - this.offset;
- hovercardTop = targetTop;
- break;
- case 'top-left':
- hovercardLeft = targetLeft - thisRect.width - this.offset;
- hovercardTop = targetTop + targetRect.height - thisRect.height;
- break;
- case 'top-right':
- hovercardLeft = targetLeft + targetRect.width + this.offset;
- hovercardTop = targetTop + targetRect.height - thisRect.height;
- break;
- }
-
- this.style.left = `${hovercardLeft}px`;
- this.style.top = `${hovercardTop}px`;
- }
-
- /**
- * Responds to a change in the `for` value and gets the updated `target`
- * element for the hovercard.
- */
- @observe('for')
- _forChanged() {
+ override connectedCallback() {
+ super.connectedCallback();
+ if (!this._target) {
this._target = this.target;
}
+ this._target.addEventListener('mouseenter', this.debounceShow);
+ this._target.addEventListener('focus', this.debounceShow);
+ this._target.addEventListener('mouseleave', this.debounceHide);
+ this._target.addEventListener('blur', this.debounceHide);
+
+ // when click, dismiss immediately
+ this._target.addEventListener('click', this.hide);
+
+ // show the hovercard if mouse moves to hovercard
+ // this will cancel pending hide as well
+ this.addEventListener('mouseenter', this.show);
+ this.addEventListener('mouseenter', this.lock);
+ // when leave hovercard, hide it immediately
+ this.addEventListener('mouseleave', this.hide);
+ this.addEventListener('mouseleave', this.unlock);
+ }
+
+ override disconnectedCallback() {
+ this.cancelShowTask();
+ this.cancelHideTask();
+ this.unlock();
+ super.disconnectedCallback();
+ }
+
+ override ready() {
+ super.ready();
+ // First, check to see if the container has already been created.
+ this.container = getHovercardContainer({createIfNotExists: true});
+ }
+
+ removeListeners() {
+ this._target?.removeEventListener('mouseenter', this.debounceShow);
+ this._target?.removeEventListener('focus', this.debounceShow);
+ this._target?.removeEventListener('mouseleave', this.debounceHide);
+ this._target?.removeEventListener('blur', this.debounceHide);
+ this._target?.removeEventListener('click', this.hide);
+ }
+
+ readonly debounceHide = () => {
+ this.cancelShowTask();
+ if (!this._isShowing || this.isScheduledToHide) return;
+ this.isScheduledToHide = true;
+ this.hideTask = debounce(
+ this.hideTask,
+ () => {
+ // This happens when hide immediately through click or mouse leave
+ // on the hovercard
+ if (!this.isScheduledToHide) return;
+ this.hide();
+ },
+ HIDE_DELAY_MS
+ );
+ };
+
+ cancelHideTask() {
+ if (this.hideTask) {
+ this.hideTask.cancel();
+ this.isScheduledToHide = false;
+ }
}
- return Mixin;
+ /**
+ * Hovercard elements are created outside of <gr-app>, so if you want to fire
+ * events, then you probably want to do that through the target element.
+ */
+
+ dispatchEventThroughTarget(eventName: string): void;
+
+ dispatchEventThroughTarget(
+ eventName: 'show-alert',
+ detail: ShowAlertEventDetail
+ ): void;
+
+ dispatchEventThroughTarget(
+ eventName: 'reload',
+ detail: ReloadEventDetail
+ ): void;
+
+ dispatchEventThroughTarget(eventName: string, detail?: unknown) {
+ if (!detail) detail = {};
+ if (this._target)
+ this._target.dispatchEvent(
+ new CustomEvent(eventName, {
+ detail,
+ bubbles: true,
+ composed: true,
+ })
+ );
+ }
+
+ /**
+ * Returns the target element that the hovercard is anchored to (the `id` of
+ * the `for` property).
+ */
+ get target(): HTMLElement {
+ const parentNode = this.parentNode;
+ // If the parentNode is a document fragment, then we need to use the host.
+ const ownerRoot = this.getRootNode() as ShadowRoot;
+ let target;
+ if (this.for) {
+ target = ownerRoot.querySelector('#' + this.for);
+ } else {
+ target =
+ !parentNode || parentNode.nodeType === Node.DOCUMENT_FRAGMENT_NODE
+ ? ownerRoot.host
+ : parentNode;
+ }
+ return target as HTMLElement;
+ }
+
+ /**
+ * unlock scroll, this will resume the scroll outside of the hovercard.
+ */
+ readonly unlock = () => {
+ removeScrollLock(this);
+ };
+
+ /**
+ * Hides/closes the hovercard. This occurs when the user triggers the
+ * `mouseleave` event on the hovercard's `target` element (as long as the
+ * user is not hovering over the hovercard).
+ *
+ */
+ readonly hide = (e?: MouseEvent) => {
+ this.cancelHideTask();
+ this.cancelShowTask();
+ if (!this._isShowing) {
+ return;
+ }
+
+ // If the user is now hovering over the hovercard or the user is returning
+ // from the hovercard but now hovering over the target (to stop an annoying
+ // flicker effect), just return.
+ if (e) {
+ if (
+ e.relatedTarget === this ||
+ (e.target === this && e.relatedTarget === this._target)
+ ) {
+ return;
+ }
+ }
+
+ // Mark that the hovercard is not visible and do not allow focusing
+ this._isShowing = false;
+
+ // Clear styles in preparation for the next time we need to show the card
+ this.classList.remove(HOVER_CLASS);
+
+ // Reset and remove the hovercard from the DOM
+ this.style.cssText = '';
+ this.$['container'].setAttribute('tabindex', '-1');
+
+ // Remove the hovercard from the container, given that it is still a child
+ // of the container.
+ if (this.container?.contains(this)) {
+ this.container.removeChild(this);
+ }
+ };
+
+ /**
+ * Shows/opens the hovercard with a fixed delay.
+ */
+ readonly debounceShow = () => {
+ this.debounceShowBy(SHOW_DELAY_MS);
+ };
+
+ /**
+ * Shows/opens the hovercard with the given delay.
+ */
+ debounceShowBy(delayMs: number) {
+ this.cancelHideTask();
+ if (this._isShowing || this.isScheduledToShow) return;
+ this.isScheduledToShow = true;
+ this.showTask = debounce(
+ this.showTask,
+ () => {
+ // This happens when the mouse leaves the target before the delay is over.
+ if (!this.isScheduledToShow) return;
+ this.show();
+ },
+ delayMs
+ );
+ }
+
+ cancelShowTask() {
+ if (this.showTask) {
+ this.showTask.cancel();
+ this.isScheduledToShow = false;
+ }
+ }
+
+ /**
+ * Lock background scroll but enable scroll inside of current hovercard.
+ */
+ readonly lock = () => {
+ pushScrollLock(this);
+ };
+
+ /**
+ * Shows/opens the hovercard. This occurs when the user triggers the
+ * `mousenter` event on the hovercard's `target` element.
+ */
+ readonly show = () => {
+ this.cancelHideTask();
+ this.cancelShowTask();
+ if (this._isShowing || !this.container) {
+ return;
+ }
+
+ // Mark that the hovercard is now visible
+ this._isShowing = true;
+ this.setAttribute('tabindex', '0');
+
+ // Add it to the DOM and calculate its position
+ this.container.appendChild(this);
+ // We temporarily hide the hovercard until we have found the correct
+ // position for it.
+ this.classList.add(HIDE_CLASS);
+ this.classList.add(HOVER_CLASS);
+ // Make sure that the hovercard actually rendered and all dom-if
+ // statements processed, so that we can measure the (invisible)
+ // hovercard properly in updatePosition().
+ flush();
+ this.updatePosition();
+ this.classList.remove(HIDE_CLASS);
+ };
+
+ updatePosition() {
+ const positionsToTry = new Set([
+ this.position,
+ 'right',
+ 'bottom-right',
+ 'top-right',
+ 'bottom',
+ 'top',
+ 'bottom-left',
+ 'top-left',
+ 'left',
+ ]);
+ for (const position of positionsToTry) {
+ this.updatePositionTo(position);
+ if (this._isInsideViewport()) return;
+ }
+ console.warn('Could not find a visible position for the hovercard.');
+ }
+
+ _isInsideViewport() {
+ const thisRect = this.getBoundingClientRect();
+ if (thisRect.top < 0) return false;
+ if (thisRect.left < 0) return false;
+ const docuRect = document.documentElement.getBoundingClientRect();
+ if (thisRect.bottom > docuRect.height) return false;
+ if (thisRect.right > docuRect.width) return false;
+ return true;
+ }
+
+ /**
+ * Updates the hovercard's position based the current position of the `target`
+ * element.
+ *
+ * The hovercard is supposed to stay open if the user hovers over it.
+ * To keep it open when the user moves away from the target, the bounding
+ * rects of the target and hovercard must touch or overlap.
+ *
+ * NOTE: You do not need to directly call this method unless you need to
+ * update the position of the tooltip while it is already visible (the
+ * target element has moved and the tooltip is still open).
+ */
+ updatePositionTo(position: string) {
+ if (!this._target) {
+ return;
+ }
+
+ // Make sure that thisRect will not get any paddings and such included
+ // in the width and height of the bounding client rect.
+ this.style.cssText = '';
+
+ const docuRect = document.documentElement.getBoundingClientRect();
+ const targetRect = this._target.getBoundingClientRect();
+ const thisRect = this.getBoundingClientRect();
+
+ const targetLeft = targetRect.left - docuRect.left;
+ const targetTop = targetRect.top - docuRect.top;
+
+ let hovercardLeft;
+ let hovercardTop;
+
+ switch (position) {
+ case 'top':
+ hovercardLeft = targetLeft + (targetRect.width - thisRect.width) / 2;
+ hovercardTop = targetTop - thisRect.height - this.offset;
+ break;
+ case 'bottom':
+ hovercardLeft = targetLeft + (targetRect.width - thisRect.width) / 2;
+ hovercardTop = targetTop + targetRect.height + this.offset;
+ break;
+ case 'left':
+ hovercardLeft = targetLeft - thisRect.width - this.offset;
+ hovercardTop = targetTop + (targetRect.height - thisRect.height) / 2;
+ break;
+ case 'right':
+ hovercardLeft = targetLeft + targetRect.width + this.offset;
+ hovercardTop = targetTop + (targetRect.height - thisRect.height) / 2;
+ break;
+ case 'bottom-right':
+ hovercardLeft = targetLeft + targetRect.width + this.offset;
+ hovercardTop = targetTop;
+ break;
+ case 'bottom-left':
+ hovercardLeft = targetLeft - thisRect.width - this.offset;
+ hovercardTop = targetTop;
+ break;
+ case 'top-left':
+ hovercardLeft = targetLeft - thisRect.width - this.offset;
+ hovercardTop = targetTop + targetRect.height - thisRect.height;
+ break;
+ case 'top-right':
+ hovercardLeft = targetLeft + targetRect.width + this.offset;
+ hovercardTop = targetTop + targetRect.height - thisRect.height;
+ break;
+ }
+
+ this.style.left = `${hovercardLeft}px`;
+ this.style.top = `${hovercardTop}px`;
+ }
+
+ /**
+ * Responds to a change in the `for` value and gets the updated `target`
+ * element for the hovercard.
+ */
+ @observe('for')
+ _forChanged() {
+ this._target = this.target;
+ }
}
-);
+
+ return Mixin as T & Constructor<GrHovercardBehaviorInterface>;
+};
export interface GrHovercardBehaviorInterface {
+ _target: HTMLElement | null;
ready(): void;
removeListeners(): void;
debounceHide(): void;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
index 8857d36..acc5e15 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard/gr-hovercard.ts
@@ -18,12 +18,15 @@
import '../../../styles/shared-styles';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-hovercard_html';
-import {hovercardBehaviorMixin} from './gr-hovercard-behavior';
+import {HovercardBehaviorMixin} from './gr-hovercard-behavior';
import './gr-hovercard-shared-style';
import {customElement} from '@polymer/decorators';
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = HovercardBehaviorMixin(PolymerElement);
+
@customElement('gr-hovercard')
-export class GrHovercard extends hovercardBehaviorMixin(PolymerElement) {
+export class GrHovercard extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
index a3d9e58..da1a782 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.ts
@@ -44,6 +44,8 @@
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
<g id="chevron-right"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path></g>
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+ <g id="more-horiz"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
+ <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
<g id="more-vert"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></g>
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
<g id="deleteEdit"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"></path></g>
@@ -154,6 +156,10 @@
<g id="file-present"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M15 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V7l-5-5zM6 20V4h8v4h4v12H6zm10-10v5c0 2.21-1.79 4-4 4s-4-1.79-4-4V8.5c0-1.47 1.26-2.64 2.76-2.49 1.3.13 2.24 1.32 2.24 2.63V15h-2V8.5c0-.28-.22-.5-.5-.5s-.5.22-.5.5V15c0 1.1.9 2 2 2s2-.9 2-2v-5h2z"/></g>
<!-- This SVG is a copy from material.io https://fonts.google.com/icons?selected=Material%20Icons%3Aarrow_forward-->
<g id="arrow-forward"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></g>
+ <!-- This SVG is a copy from material.io https://fonts.google.com/icons?selected=Material+Icons:feedback -->
+ <g id="feedback"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 12h-2v-2h2v2zm0-4h-2V6h2v4z"/></g>
+ <!-- This SVG is a copy from material.io https://fonts.google.com/icons?selected=Material+Icons&icon.query=description -->
+ <g id="description"><path xmlns="http://www.w3.org/2000/svg" d="M0 0h24v24H0V0z" fill="none"/><path xmlns="http://www.w3.org/2000/svg" d="M8 16h8v2H8zm0-4h8v2H8zm6-10H6c-1.1 0-2 .9-2 2v16c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/></g>
</defs>
</svg>
</iron-iconset-svg>`;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.ts
similarity index 70%
rename from polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js
rename to polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.ts
index e45cb0c..865aa20 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-api-utils_test.ts
@@ -15,9 +15,9 @@
* limitations under the License.
*/
-import '../../../test/common-test-setup-karma.js';
-import './gr-js-api-interface.js';
-import {getPluginNameFromUrl} from './gr-api-utils.js';
+import '../../../test/common-test-setup-karma';
+import './gr-js-api-interface';
+import {getPluginNameFromUrl} from './gr-api-utils';
suite('gr-api-utils tests', () => {
suite('test getPluginNameFromUrl', () => {
@@ -32,37 +32,36 @@
test('with random invalid url', () => {
assert.equal(getPluginNameFromUrl('http://example.com'), null);
assert.equal(
- getPluginNameFromUrl('http://example.com/static/a.js'),
- null
+ getPluginNameFromUrl('http://example.com/static/a.js'),
+ null
);
});
test('with valid urls', () => {
assert.equal(
- getPluginNameFromUrl('http://example.com/plugins/a.js'),
- 'a'
+ getPluginNameFromUrl('http://example.com/plugins/a.js'),
+ 'a'
);
assert.equal(
- getPluginNameFromUrl('http://example.com/plugins/a/static/t.js'),
- 'a'
+ getPluginNameFromUrl('http://example.com/plugins/a/static/t.js'),
+ 'a'
);
});
test('with gerrit-theme override', () => {
assert.equal(
- getPluginNameFromUrl('http://example.com/static/gerrit-theme.js'),
- 'gerrit-theme'
+ getPluginNameFromUrl('http://example.com/static/gerrit-theme.js'),
+ 'gerrit-theme'
);
});
test('with ASSETS_PATH', () => {
window.ASSETS_PATH = 'http://cdn.com/2';
assert.equal(
- getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.js`),
- 'a'
+ getPluginNameFromUrl(`${window.ASSETS_PATH}/plugins/a.js`),
+ 'a'
);
window.ASSETS_PATH = undefined;
});
});
});
-
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 466e8e4..a33b145 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
@@ -90,7 +90,7 @@
* Ensure GrChangeActionsInterface instance has access to gr-change-actions
* element and retrieve if the interface was created before element.
*/
- private ensureEl(): GrChangeActionsElement {
+ ensureEl(): GrChangeActionsElement {
if (!this.el) {
const sharedApiElement = appContext.jsApiService;
this.setEl(
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.js
index 203784d..87f6052 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api_test.js
@@ -125,7 +125,7 @@
.querySelector('[data-action-key="' + key + '"]'));
});
- test('action button properties', () => {
+ test('action button properties', async () => {
const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
flush();
const button = element.shadowRoot
@@ -137,17 +137,17 @@
changeActions.setTitle(key, 'Yo hint');
changeActions.setEnabled(key, false);
changeActions.setIcon(key, 'pupper');
- flush();
+ await flush();
assert.equal(button.getAttribute('data-label'), 'Yo');
- assert.equal(button.getAttribute('title'), 'Yo hint');
+ assert.equal(button.parentElement.getAttribute('title'), 'Yo hint');
assert.isTrue(button.disabled);
assert.equal(button.querySelector('iron-icon').icon,
'gr-icons:pupper');
});
- test('hide action buttons', () => {
+ test('hide action buttons', async () => {
const key = changeActions.add(changeActions.ActionType.REVISION, 'Bork!');
- flush();
+ await flush();
let button = element.shadowRoot
.querySelector('[data-action-key="' + key + '"]');
assert.isOk(button);
@@ -168,7 +168,7 @@
.querySelector('[data-action-key="' + key + '"]'));
changeActions.setActionOverflow(
changeActions.ActionType.REVISION, key, true);
- flush();
+ await flush();
assert.isNotOk(element.shadowRoot
.querySelector('[data-action-key="' + key + '"]'));
assert.isFalse(element.$.moreActions.hidden);
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 3ee393c..1d4bd06 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
@@ -31,8 +31,10 @@
} from '../../../services/gr-event-interface/gr-event-interface';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {Gerrit} from '../../../api/gerrit';
+import {fontStyles} from '../../../styles/gr-font-styles';
import {formStyles} from '../../../styles/gr-form-styles';
import {menuPageStyles} from '../../../styles/gr-menu-page-styles';
+import {spinnerStyles} from '../../../styles/gr-spinner-styles';
import {subpageStyles} from '../../../styles/gr-subpage-styles';
import {tableStyles} from '../../../styles/gr-table-styles';
@@ -121,8 +123,10 @@
public readonly Auth = appContext.authService;
public readonly styles = {
+ font: fontStyles,
form: formStyles,
menuPage: menuPageStyles,
+ spinner: spinnerStyles,
subPage: subpageStyles,
table: tableStyles,
};
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 8ec2607..29db685 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
@@ -23,7 +23,6 @@
import {getPluginLoader} from './gr-plugin-loader.js';
import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
import {stubBaseUrl} from '../../../test/test-utils.js';
-import sinon from 'sinon/pkg/sinon-esm';
import {stubRestApi} from '../../../test/test-utils.js';
import {appContext} from '../../../services/app-context.js';
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 f7475bf..b039a7e 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
@@ -104,7 +104,7 @@
* which endpoints to dynamically add to the page.
*/
registerModule(plugin: PluginApi, opts: Options) {
- const endpoint = opts.endpoint!;
+ const endpoint = opts.endpoint;
const dynamicEndpoint = opts.dynamicEndpoint;
if (dynamicEndpoint) {
if (!this._dynamicPlugins.has(dynamicEndpoint)) {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
deleted file mode 100644
index e3475ad..0000000
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.js
+++ /dev/null
@@ -1,166 +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 '../../../test/common-test-setup-karma.js';
-import {resetPlugins} from '../../../test/test-utils.js';
-import './gr-js-api-interface.js';
-import {GrPluginEndpoints} from './gr-plugin-endpoints.js';
-import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
-
-const pluginApi = _testOnly_initGerritPluginApi();
-
-suite('gr-plugin-endpoints tests', () => {
- let instance;
- let pluginFoo;
- let pluginBar;
- let domHook;
-
- setup(() => {
- domHook = {};
- instance = new GrPluginEndpoints();
- pluginApi.install(p => { pluginFoo = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/foo.js');
- instance.registerModule(
- pluginFoo,
- {
- endpoint: 'a-place',
- type: 'decorate',
- moduleName: 'foo-module',
- domHook,
- }
- );
- pluginApi.install(p => { pluginBar = p; }, '0.1',
- 'http://test.com/plugins/testplugin/static/bar.js');
- instance.registerModule(
- pluginBar,
- {
- endpoint: 'a-place',
- type: 'style',
- moduleName: 'bar-module',
- domHook,
- }
- );
- });
-
- teardown(() => {
- resetPlugins();
- });
-
- test('getDetails all', () => {
- assert.deepEqual(instance.getDetails('a-place'), [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getDetails by type', () => {
- assert.deepEqual(instance.getDetails('a-place', {type: 'style'}), [
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getDetails by module', () => {
- assert.deepEqual(
- instance.getDetails('a-place', {moduleName: 'foo-module'}),
- [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- ]);
- });
-
- test('getModules', () => {
- assert.deepEqual(
- instance.getModules('a-place'), ['foo-module', 'bar-module']);
- });
-
- test('getPlugins', () => {
- assert.deepEqual(
- instance.getPlugins('a-place'), [pluginFoo._url]);
- });
-
- test('onNewEndpoint', () => {
- const newModuleStub = sinon.stub();
- instance.setPluginsReady();
- instance.onNewEndpoint('a-place', newModuleStub);
- instance.registerModule(
- pluginFoo,
- {
- endpoint: 'a-place',
- type: 'replace',
- moduleName: 'zaz-module',
- domHook,
- });
- assert.deepEqual(newModuleStub.lastCall.args[0], {
- moduleName: 'zaz-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'replace',
- domHook,
- slot: undefined,
- });
- });
-
- test('reuse dom hooks', () => {
- instance.registerModule(
- pluginFoo, 'a-place', 'decorate', 'foo-module', domHook);
- assert.deepEqual(instance.getDetails('a-place'), [
- {
- moduleName: 'foo-module',
- plugin: pluginFoo,
- pluginUrl: pluginFoo._url,
- type: 'decorate',
- domHook,
- slot: undefined,
- },
- {
- moduleName: 'bar-module',
- plugin: pluginBar,
- pluginUrl: pluginBar._url,
- type: 'style',
- domHook,
- slot: undefined,
- },
- ]);
- });
-});
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts
new file mode 100644
index 0000000..c7bdfb4
--- /dev/null
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints_test.ts
@@ -0,0 +1,177 @@
+/**
+ * @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 '../../../test/common-test-setup-karma';
+import {resetPlugins} from '../../../test/test-utils';
+import './gr-js-api-interface';
+import {GrPluginEndpoints} from './gr-plugin-endpoints';
+import {_testOnly_initGerritPluginApi} from './gr-gerrit';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi, HookCallback, PluginElement} from '../../../api/hook';
+
+const pluginApi = _testOnly_initGerritPluginApi();
+
+export class MockHook<T extends PluginElement> implements HookApi<T> {
+ handleInstanceDetached(_: T) {}
+
+ handleInstanceAttached(_: T) {}
+
+ getLastAttached(): Promise<HTMLElement> {
+ throw new Error('unimplemented in mock');
+ }
+
+ getAllAttached() {
+ return [];
+ }
+
+ onAttached(_: HookCallback<T>) {
+ return this;
+ }
+
+ onDetached(_: HookCallback<T>) {
+ return this;
+ }
+
+ getModuleName() {
+ return 'MockHookApi-ModuleName';
+ }
+}
+
+suite('gr-plugin-endpoints tests', () => {
+ let instance: GrPluginEndpoints;
+ let decoratePlugin: PluginApi;
+ let stylePlugin: PluginApi;
+ let domHook: HookApi<PluginElement>;
+
+ setup(() => {
+ domHook = new MockHook<PluginElement>();
+ instance = new GrPluginEndpoints();
+ pluginApi.install(
+ plugin => (decoratePlugin = plugin),
+ '0.1',
+ 'http://test.com/plugins/testplugin/static/decorate.js'
+ );
+ instance.registerModule(decoratePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'decorate',
+ moduleName: 'decorate-module',
+ domHook,
+ });
+ pluginApi.install(
+ plugin => (stylePlugin = plugin),
+ '0.1',
+ 'http://test.com/plugins/testplugin/static/style.js'
+ );
+ instance.registerModule(stylePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'style',
+ moduleName: 'style-module',
+ domHook,
+ });
+ });
+
+ teardown(() => {
+ resetPlugins();
+ });
+
+ test('getDetails all', () => {
+ assert.deepEqual(instance.getDetails('my-endpoint'), [
+ {
+ moduleName: 'decorate-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'decorate',
+ domHook,
+ slot: undefined,
+ },
+ {
+ moduleName: 'style-module',
+ plugin: stylePlugin,
+ pluginUrl: stylePlugin._url,
+ type: 'style',
+ domHook,
+ slot: undefined,
+ },
+ ]);
+ });
+
+ test('getDetails by type', () => {
+ assert.deepEqual(
+ instance.getDetails('my-endpoint', {endpoint: 'a-place', type: 'style'}),
+ [
+ {
+ moduleName: 'style-module',
+ plugin: stylePlugin,
+ pluginUrl: stylePlugin._url,
+ type: 'style',
+ domHook,
+ slot: undefined,
+ },
+ ]
+ );
+ });
+
+ test('getDetails by module', () => {
+ assert.deepEqual(
+ instance.getDetails('my-endpoint', {
+ endpoint: 'my-endpoint',
+ moduleName: 'decorate-module',
+ }),
+ [
+ {
+ moduleName: 'decorate-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'decorate',
+ domHook,
+ slot: undefined,
+ },
+ ]
+ );
+ });
+
+ test('getModules', () => {
+ assert.deepEqual(instance.getModules('my-endpoint'), [
+ 'decorate-module',
+ 'style-module',
+ ]);
+ });
+
+ test('getPlugins URLs are unique', () => {
+ assert.equal(decoratePlugin._url, stylePlugin._url);
+ assert.deepEqual(instance.getPlugins('my-endpoint'), [decoratePlugin._url]);
+ });
+
+ test('onNewEndpoint', () => {
+ const newModuleStub = sinon.stub();
+ instance.setPluginsReady();
+ instance.onNewEndpoint('my-endpoint', newModuleStub);
+ instance.registerModule(decoratePlugin, {
+ endpoint: 'my-endpoint',
+ type: 'replace',
+ moduleName: 'replace-module',
+ domHook,
+ });
+ assert.deepEqual(newModuleStub.lastCall.args[0], {
+ moduleName: 'replace-module',
+ plugin: decoratePlugin,
+ pluginUrl: decoratePlugin._url,
+ type: 'replace',
+ domHook,
+ slot: undefined,
+ });
+ });
+});
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 6fc8f1b..7c99480 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
@@ -123,7 +123,10 @@
});
this.awaitPluginsLoaded().then(() => {
- this._getReporting().pluginsLoaded(this._getAllInstalledPluginNames());
+ const loaded = this.getPluginsByState(PluginState.LOADED);
+ const failed = this.getPluginsByState(PluginState.LOAD_FAILED);
+ this._getReporting().pluginsLoaded(loaded.map(p => p.name));
+ this._getReporting().pluginsFailed(failed.map(p => p.name));
});
}
@@ -140,14 +143,8 @@
return url.pathname && url.pathname.endsWith(suffix);
}
- _getAllInstalledPluginNames() {
- const installedPlugins = [];
- for (const plugin of this._plugins.values()) {
- if (plugin.state === PluginState.LOADED) {
- installedPlugins.push(plugin.name);
- }
- }
- return installedPlugins;
+ private getPluginsByState(state: PluginState) {
+ return [...this._plugins.values()].filter(p => p.state === state);
}
install(
@@ -190,16 +187,9 @@
}
}
- // The polygerrit uses version of sinon where you can't stub getter,
- // declare it as a function here
arePluginsLoaded() {
- // As the size of plugins is relatively small,
- // so the performance of this check should be reasonable
if (!this._pluginListLoaded) return false;
- for (const plugin of this._plugins.values()) {
- if (plugin.state === PluginState.PENDING) return false;
- }
- return true;
+ return this.getPluginsByState(PluginState.PENDING).length === 0;
}
_checkIfCompleted() {
@@ -214,15 +204,14 @@
}
_timeout() {
- const pendingPlugins = [];
- for (const plugin of this._plugins.values()) {
- if (plugin.state === PluginState.PENDING) {
- this._updatePluginState(plugin.url, PluginState.LOAD_FAILED);
- this._checkIfCompleted();
- pendingPlugins.push(plugin.url);
- }
+ const pending = this.getPluginsByState(PluginState.PENDING);
+ for (const plugin of pending) {
+ this._updatePluginState(plugin.url, PluginState.LOAD_FAILED);
}
- return `Timeout when loading plugins: ${pendingPlugins.join(',')}`;
+ this._checkIfCompleted();
+ return `Timeout when loading plugins: ${pending
+ .map(p => p.name)
+ .join(',')}`;
}
_failToLoad(message: string, pluginUrl?: string) {
@@ -252,6 +241,7 @@
plugin: null,
});
}
+ console.info(`Plugin ${key} ${state}`);
return this._plugins.get(key)!;
}
@@ -259,7 +249,6 @@
const pluginObj = this._updatePluginState(url, PluginState.LOADED);
pluginObj.plugin = plugin;
this._getReporting().pluginLoaded(plugin.getPluginName() || url);
- console.info(`Plugin ${plugin.getPluginName() || url} installed.`);
this._checkIfCompleted();
}
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 903fb2c..2b6db21 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
@@ -68,11 +68,6 @@
return this.restApi.getAccount();
}
- getAccountCapabilities(capabilities: string[]) {
- this.reporting.trackApi(this.plugin, 'rest', 'getAccountCapabilities');
- return this.restApi.getAccountCapabilities(capabilities);
- }
-
getRepos(filter: string, reposPerPage: number, offset?: number) {
this.reporting.trackApi(this.plugin, 'rest', 'getRepos');
return this.restApi.getRepos(filter, reposPerPage, offset);
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 31a709a..dba36a4 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
@@ -14,6 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/gr-font-styles';
import '../../../styles/gr-voting-styles';
import '../../../styles/shared-styles';
import '../gr-account-label/gr-account-label';
@@ -21,6 +22,7 @@
import '../gr-button/gr-button';
import '../gr-icons/gr-icons';
import '../gr-label/gr-label';
+import '../gr-tooltip-content/gr-tooltip-content';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {PolymerElement} from '@polymer/polymer/polymer-element';
import {htmlTemplate} from './gr-label-info_html';
@@ -38,6 +40,7 @@
import {GrButton} from '../gr-button/gr-button';
import {getVotingRangeOrDefault} from '../../../utils/label-util';
import {appContext} from '../../../services/app-context';
+import {ParsedChangeInfo} from '../../../types/types';
declare global {
interface HTMLElementTagNameMap {
@@ -71,7 +74,7 @@
label = '';
@property({type: Object})
- change?: ChangeInfo;
+ change?: ParsedChangeInfo;
@property({type: Object})
account?: AccountInfo;
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
index b6583d9..552bd08 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
@@ -17,6 +17,9 @@
import {html} from '@polymer/polymer/lib/utils/html-tag';
export const htmlTemplate = html`
+ <style include="gr-font-styles">
+ /* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
+ </style>
<style include="gr-voting-styles">
/* Workaround for empty style block - see https://github.com/Polymer/tools/issues/408 */
</style>
@@ -27,13 +30,13 @@
.hidden {
display: none;
}
+ /* Note that most of the .voteChip styles are coming from the
+ gr-voting-styles include. */
.voteChip {
display: flex;
justify-content: center;
margin-right: var(--spacing-s);
padding: 1px;
- @apply --vote-chip-styles;
- border: 1px solid var(--border-color);
}
.max {
background-color: var(--vote-color-approved);
@@ -98,13 +101,14 @@
>
<tr class="labelValueContainer">
<td>
- <gr-label
- has-tooltip=""
+ <gr-tooltip-content
+ has-tooltip
title="[[_computeValueTooltip(labelInfo, mappedLabel.value)]]"
- class$="[[mappedLabel.className]] voteChip font-small"
>
- [[mappedLabel.value]]
- </gr-label>
+ <gr-label class$="[[mappedLabel.className]] voteChip font-small">
+ [[mappedLabel.value]]
+ </gr-label>
+ </gr-tooltip-content>
</td>
<td>
<gr-account-link
@@ -113,16 +117,17 @@
></gr-account-link>
</td>
<td>
- <gr-button
- link=""
- aria-label="Remove vote"
- on-click="_onDeleteVote"
- tooltip="Remove vote"
- data-account-id$="[[mappedLabel.account._account_id]]"
- class$="deleteBtn [[_computeDeleteClass(mappedLabel.account, mutable, change)]]"
- >
- <iron-icon icon="gr-icons:delete"></iron-icon>
- </gr-button>
+ <gr-tooltip-content has-tooltip title="Remove vote">
+ <gr-button
+ link=""
+ aria-label="Remove vote"
+ on-click="_onDeleteVote"
+ data-account-id$="[[mappedLabel.account._account_id]]"
+ class$="deleteBtn [[_computeDeleteClass(mappedLabel.account, mutable, change)]]"
+ >
+ <iron-icon icon="gr-icons:delete"></iron-icon>
+ </gr-button>
+ </gr-tooltip-content>
</td>
</tr>
</template>
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
index b3235fa..b1bd6fa 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.ts
@@ -31,7 +31,7 @@
import {GrAccountLink} from '../gr-account-link/gr-account-link';
import {
createAccountWithIdNameAndEmail,
- createChange,
+ createParsedChange,
} from '../../../test/test-data-generators';
import {LabelInfo} from '../../../types/common';
@@ -46,7 +46,7 @@
// Needed to trigger computed bindings.
element.account = {};
- element.change = {...createChange(), labels: {}};
+ element.change = {...createParsedChange(), labels: {}};
});
suite('remove reviewer votes', () => {
@@ -60,7 +60,7 @@
sinon.stub(element, '_computeValueTooltip').returns('');
element.account = account;
element.change = {
- ...createChange(),
+ ...createParsedChange(),
labels: {'Code-Review': label},
};
element.labelInfo = label;
diff --git a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
index c13ca6e..842b35e 100644
--- a/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label/gr-label.ts
@@ -21,10 +21,8 @@
* used in gr-label-info.
*/
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {customElement} from '@polymer/decorators';
-import {htmlTemplate} from './gr-label_html';
-import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
+import {html, LitElement} from 'lit';
+import {customElement} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -33,8 +31,12 @@
}
@customElement('gr-label')
-export class GrLabel extends TooltipMixin(PolymerElement) {
- static get template() {
- return htmlTemplate;
+export class GrLabel extends LitElement {
+ static override get styles() {
+ return [];
+ }
+
+ override render() {
+ return html` <slot></slot> `;
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
index 4a2ba86..7008db2 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text.ts
@@ -14,10 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-limited-text_html';
-import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
-import {customElement, observe, property} from '@polymer/decorators';
+import {customElement, property} from 'lit/decorators';
+import {html, LitElement} from 'lit';
declare global {
interface HTMLElementTagNameMap {
@@ -32,57 +30,56 @@
* and a tooltip containing the full text is enabled.
*/
@customElement('gr-limited-text')
-export class GrLimitedText extends TooltipMixin(PolymerElement) {
- static get template() {
- return htmlTemplate;
- }
-
+export class GrLimitedText extends LitElement {
/** The un-truncated text to display. */
@property({type: String})
- text?: string;
+ text = '';
/** The maximum length for the text to display before truncating. */
@property({type: Number})
- limit?: number;
+ limit = 0;
@property({type: String})
tooltip?: string;
- /** Boolean property used by TooltipMixin. */
- @property({type: Boolean})
- override hasTooltip = false;
+ static override get styles() {
+ return [];
+ }
- /** Boolean property used by TooltipMixin. */
- @property({type: Boolean})
- disableTooltip = false;
-
- /**
- * The text or limit have changed. Recompute whether a tooltip needs to be
- * enabled.
- */
- @observe('text', 'tooltip', 'limit')
- _updateTitle(text?: string, tooltip?: string, limit?: number) {
- text = text ?? '';
- tooltip = tooltip ?? '';
- limit = limit ?? 0;
-
- this.hasTooltip = !!tooltip || (!!limit && text.length > limit);
- if (this.hasTooltip && !this.disableTooltip) {
- // Combine the text and title if over-length
- if (limit && text.length > limit) {
- this.title = `${text}${tooltip ? ` (${tooltip})` : ''}`;
- } else {
- this.title = tooltip;
- }
+ override render() {
+ if (this.tooltip || this.tooLong()) {
+ return html` <gr-tooltip-content
+ has-tooltip
+ .title=${this.renderTooltip()}
+ >
+ ${this.renderText()}
+ </gr-tooltip-content>`;
} else {
- this.title = '';
+ return this.renderText();
}
}
- _computeDisplayText(text?: string, limit?: number) {
- if (!!limit && !!text && text.length > limit) {
- return text.substr(0, limit - 1) + '…';
+ // Should be private but used in tests.
+ renderText() {
+ if (this.tooLong()) {
+ return this.text.substr(0, this.limit - 1) + '…';
}
- return text;
+ return this.text;
+ }
+
+ private renderTooltip() {
+ if (this.tooLong()) {
+ return `${this.text}${this.tooltip ? ` (${this.tooltip})` : ''}`;
+ } else if (this.tooltip) {
+ return this.tooltip;
+ } else {
+ return '';
+ }
+ }
+
+ private tooLong() {
+ if (!this.limit) return false;
+ if (!this.text) return false;
+ return this.text.length > this.limit;
}
}
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_html.ts b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_html.ts
deleted file mode 100644
index b942d07..0000000
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_html.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html` [[_computeDisplayText(text, limit)]] `;
diff --git a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.js b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.js
index 3b99d6d..e3e72d0 100644
--- a/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-limited-text/gr-limited-text_test.js
@@ -23,77 +23,65 @@
suite('gr-limited-text tests', () => {
let element;
- setup(() => {
+ setup(async () => {
element = basicFixture.instantiate();
+ await element.updateComplete;
});
- test('tooltip without title input', () => {
- const updateSpy = sinon.spy(element, '_updateTitle');
+ test('tooltip without title input', async () => {
element.text = 'abc 123';
- flush();
- assert.isTrue(updateSpy.calledOnce);
- assert.isNotOk(element.getAttribute('title'));
- assert.isFalse(element.hasTooltip);
+ await element.updateComplete;
+ assert.isNotOk(element.shadowRoot.querySelector('gr-tooltip-content'));
element.limit = 10;
- flush();
- assert.isTrue(updateSpy.calledTwice);
- assert.isNotOk(element.getAttribute('title'));
- assert.isFalse(element.hasTooltip);
+ await element.updateComplete;
+ assert.isNotOk(element.shadowRoot.querySelector('gr-tooltip-content'));
element.limit = 3;
- flush();
- assert.equal(updateSpy.callCount, 3);
- assert.equal(element.getAttribute('title'), 'abc 123');
- assert.equal(element.title, 'abc 123');
- assert.isTrue(element.hasTooltip);
+ await element.updateComplete;
+ assert.isOk(element.shadowRoot.querySelector('gr-tooltip-content'));
+ assert.equal(
+ element.shadowRoot.querySelector('gr-tooltip-content').title,
+ 'abc 123');
element.limit = 100;
- flush();
- assert.equal(updateSpy.callCount, 4);
- assert.isFalse(element.hasTooltip);
+ await element.updateComplete;
+ assert.isNotOk(element.shadowRoot.querySelector('gr-tooltip-content'));
element.limit = null;
- flush();
- assert.equal(updateSpy.callCount, 5);
- assert.isNotOk(element.getAttribute('title'));
- assert.isFalse(element.hasTooltip);
+ await element.updateComplete;
+ assert.isNotOk(element.shadowRoot.querySelector('gr-tooltip-content'));
});
- test('with tooltip input', () => {
- const updateSpy = sinon.spy(element, '_updateTitle');
+ test('with tooltip input', async () => {
element.tooltip = 'abc 123';
- flush();
- assert.isTrue(updateSpy.calledOnce);
- assert.isTrue(element.hasTooltip);
- assert.equal(element.getAttribute('title'), 'abc 123');
- assert.equal(element.title, 'abc 123');
+ await element.updateComplete;
+ let tooltipContent = element.shadowRoot.querySelector('gr-tooltip-content');
+ assert.isOk(tooltipContent);
+ assert.equal(tooltipContent.title, 'abc 123');
element.text = 'abc';
- flush();
- assert.equal(element.getAttribute('title'), 'abc 123');
- assert.isTrue(element.hasTooltip);
+ await element.updateComplete;
+ tooltipContent = element.shadowRoot.querySelector('gr-tooltip-content');
+ assert.isOk(tooltipContent);
+ assert.equal(tooltipContent.title, 'abc 123');
element.text = 'abcdef';
element.limit = 3;
- flush();
- assert.equal(element.getAttribute('title'), 'abcdef (abc 123)');
- assert.isTrue(element.hasTooltip);
+ await element.updateComplete;
+ tooltipContent = element.shadowRoot.querySelector('gr-tooltip-content');
+ assert.isOk(tooltipContent);
+ assert.equal(tooltipContent.title, 'abcdef (abc 123)');
});
test('_computeDisplayText', () => {
- assert.equal(element._computeDisplayText('foo bar', 100), 'foo bar');
- assert.equal(element._computeDisplayText('foo bar', 4), 'foo…');
- assert.equal(element._computeDisplayText('foo bar', null), 'foo bar');
- });
-
- test('when disable tooltip', () => {
- sinon.spy(element, '_updateTitle');
- element.text = 'abcdefghijklmn';
- element.disableTooltip = true;
- element.limit = 10;
- flush();
- assert.equal(element.getAttribute('title'), '');
+ element.text = 'foo bar';
+ element.limit = 100;
+ assert.equal(element.renderText(), 'foo bar');
+ element.limit = 4;
+ assert.equal(element.renderText(), 'foo…');
+ element.limit = 0;
+ assert.equal(element.renderText(), 'foo bar');
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
index b74d643..801b8bf 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-chip/gr-linked-chip.ts
@@ -20,8 +20,8 @@
import '../gr-limited-text/gr-limited-text';
import {fireEvent} from '../../../utils/event-util';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -30,7 +30,7 @@
}
@customElement('gr-linked-chip')
-export class GrLinkedChip extends GrLitElement {
+export class GrLinkedChip extends LitElement {
@property({type: String})
href = '';
@@ -50,7 +50,7 @@
@property({type: Number})
limit?: number;
- static get styles() {
+ static override get styles() {
return [
sharedStyles,
css`
@@ -84,9 +84,10 @@
];
}
- render() {
+ override render() {
// To pass CSS mixins for @apply to Polymer components, they need to appear
// in <style> inside the template.
+ /* eslint-disable lit/prefer-static-styles */
const customStyle = html`
<style>
gr-button::part(paper-button),
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
index 5d72925..2812b47 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text.ts
@@ -14,10 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+import '../../../styles/shared-styles';
+import {PolymerElement} from '@polymer/polymer/polymer-element';
+import {htmlTemplate} from './gr-linked-text_html';
import {GrLinkTextParser, LinkTextParserConfig} from './link-text-parser';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property, query} from 'lit-element';
+import {customElement, property, observe} from '@polymer/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -25,10 +27,17 @@
}
}
+export interface GrLinkedText {
+ $: {
+ output: HTMLSpanElement;
+ };
+}
+
@customElement('gr-linked-text')
-export class GrLinkedText extends GrLitElement {
- @query('#output')
- outputElement?: HTMLSpanElement;
+export class GrLinkedText extends PolymerElement {
+ static get template() {
+ return htmlTemplate;
+ }
@property({type: Boolean})
removeZeroWidthSpace?: boolean;
@@ -37,63 +46,61 @@
@property({type: String})
content: string | null = null;
- @property({type: Boolean, reflect: true})
+ @property({type: Boolean, reflectToAttribute: true})
pre = false;
- @property({type: Boolean, reflect: true})
+ @property({type: Boolean, reflectToAttribute: true})
disabled = false;
@property({type: Object})
config?: LinkTextParserConfig;
- static override get styles() {
- return [
- css`
- :host {
- display: block;
- }
- :host([pre]) span {
- white-space: var(--linked-text-white-space, pre-wrap);
- word-wrap: var(--linked-text-word-wrap, break-word);
- }
- :host([disabled]) a {
- color: inherit;
- text-decoration: none;
- pointer-events: none;
- }
- a {
- color: var(--link-color);
- }
- `,
- ];
- }
-
- override render() {
+ @observe('content')
+ _contentChanged(content: string | null) {
+ // In the case where the config may not be set (perhaps due to the
+ // request for it still being in flight), set the content anyway to
+ // prevent waiting on the config to display the text.
if (!this.config) {
return;
}
- return html`<span id="output">${this.content}</span>`;
+ this.$.output.textContent = content;
}
- override updated() {
- if (!this.outputElement || !this.config) return;
- this.outputElement.textContent = '';
+ /**
+ * Because either the source text or the linkification config has changed,
+ * the content should be re-parsed.
+ *
+ * @param content The raw, un-linkified source string to parse.
+ * @param config The server config specifying commentLink patterns
+ */
+ @observe('content', 'config')
+ _contentOrConfigChanged(
+ content: string | null,
+ config?: LinkTextParserConfig
+ ) {
+ if (!config) {
+ return;
+ }
+
// TODO(TS): mapCommentlinks always has value, remove
if (!GerritNav.mapCommentlinks) return;
- const config = GerritNav.mapCommentlinks(this.config);
+ config = GerritNav.mapCommentlinks(config);
+ const output = this.$.output;
+ output.textContent = '';
const parser = new GrLinkTextParser(
config,
(text: string | null, href: string | null, fragment?: DocumentFragment) =>
this._handleParseResult(text, href, fragment),
this.removeZeroWidthSpace
);
- parser.parse(this.content);
+ parser.parse(content);
+
// Ensure that external links originating from HTML commentlink configs
// open in a new tab. @see Issue 5567
// Ensure links to the same host originating from commentlink configs
// open in the same tab. When target is not set - default is _self
// @see Issue 4616
- this.outputElement.querySelectorAll('a').forEach(anchor => {
+ output.querySelectorAll('a').forEach(anchor => {
if (anchor.hostname === window.location.hostname) {
anchor.removeAttribute('target');
} else {
@@ -117,8 +124,7 @@
href: string | null,
fragment?: DocumentFragment
) {
- const output = this.outputElement;
- if (!output) return;
+ const output = this.$.output;
if (href) {
const a = document.createElement('a');
a.setAttribute('href', href);
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_html.ts
similarity index 69%
rename from polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
rename to polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_html.ts
index 4808832..0d44bc8 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_html.ts
@@ -19,12 +19,20 @@
export const htmlTemplate = html`
<style>
:host {
+ display: block;
+ }
+ :host([pre]) span {
+ white-space: var(--linked-text-white-space, pre-wrap);
+ word-wrap: var(--linked-text-word-wrap, break-word);
+ }
+ :host([disabled]) a {
color: inherit;
- display: inline;
+ text-decoration: none;
+ pointer-events: none;
+ }
+ a {
+ color: var(--link-color);
}
</style>
- <span>
- [[_computeDateStr(dateStr, _timeFormat, _dateFormat, _relative,
- showDateAndTime, showYesterday)]]
- </span>
+ <span id="output"></span>
`;
diff --git a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.ts b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.ts
index c97c168..b2cdba1 100644
--- a/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-linked-text/gr-linked-text_test.ts
@@ -85,11 +85,10 @@
window.CANONICAL_PATH = originalCanonicalPath;
});
- test('URL pattern was parsed and linked.', async () => {
+ test('URL pattern was parsed and linked.', () => {
// Regular inline link.
const url = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
element.content = url;
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.equal(linkEl.target, '_blank');
@@ -98,10 +97,9 @@
assert.equal(linkEl.textContent, url);
});
- test('Bug pattern was parsed and linked', async () => {
+ test('Bug pattern was parsed and linked', () => {
// "Issue/Bug" pattern.
element.content = 'Issue 3650';
- await flush();
let linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
@@ -111,7 +109,6 @@
assert.equal(linkEl.textContent, 'Issue 3650');
element.content = 'Bug 3650';
- await flush();
linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.equal(linkEl.target, '_blank');
@@ -120,10 +117,10 @@
assert.equal(linkEl.textContent, 'Bug 3650');
});
- test('Pattern with same prefix as link was correctly parsed', async () => {
+ test('Pattern with same prefix as link was correctly parsed', () => {
// Pattern starts with the same prefix (`http`) as the url.
element.content = 'httpexample 3650';
- await flush();
+
assert.equal(queryAndAssert(element, '#output').childNodes.length, 1);
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
@@ -133,12 +130,12 @@
assert.equal(linkEl.textContent, 'httpexample 3650');
});
- test('Change-Id pattern was parsed and linked', async () => {
+ test('Change-Id pattern was parsed and linked', () => {
// "Change-Id:" pattern.
const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
const prefix = 'Change-Id: ';
element.content = prefix + changeID;
- await flush();
+
const textNode = queryAndAssert(element, '#output').childNodes[0];
const linkEl = queryAndAssert(element, '#output')
.childNodes[1] as HTMLAnchorElement;
@@ -150,14 +147,14 @@
assert.equal(linkEl.textContent, changeID);
});
- test('Change-Id pattern was parsed and linked with base url', async () => {
+ test('Change-Id pattern was parsed and linked with base url', () => {
window.CANONICAL_PATH = '/r';
// "Change-Id:" pattern.
const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
const prefix = 'Change-Id: ';
element.content = prefix + changeID;
- await flush();
+
const textNode = queryAndAssert(element, '#output').childNodes[0];
const linkEl = queryAndAssert(element, '#output')
.childNodes[1] as HTMLAnchorElement;
@@ -169,9 +166,8 @@
assert.equal(linkEl.textContent, changeID);
});
- test('Multiple matches', async () => {
+ test('Multiple matches', () => {
element.content = 'Issue 3650\nIssue 3450';
- await flush();
const linkEl1 = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
const linkEl2 = queryAndAssert(element, '#output')
@@ -192,7 +188,7 @@
assert.equal(linkEl2.textContent, 'Issue 3450');
});
- test('Change-Id pattern parsed before bug pattern', async () => {
+ test('Change-Id pattern parsed before bug pattern', () => {
// "Change-Id:" pattern.
const changeID = 'I11d6a37f5e9b5df0486f6c922d8836dfa780e03e';
const prefix = 'Change-Id: ';
@@ -204,7 +200,7 @@
const bugUrl = 'https://bugs.chromium.org/p/gerrit/issues/detail?id=3650';
element.content = prefix + changeID + bug;
- await flush();
+
const textNode = queryAndAssert(element, '#output').childNodes[0];
const changeLinkEl = queryAndAssert(element, '#output')
.childNodes[1] as HTMLAnchorElement;
@@ -222,9 +218,8 @@
assert.equal(bugLinkEl.textContent, 'Issue 3650');
});
- test('html field in link config', async () => {
+ test('html field in link config', () => {
element.content = 'google:do a barrel roll';
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.equal(
@@ -234,58 +229,52 @@
assert.equal(linkEl.textContent, 'do a barrel roll');
});
- test('removing hash from links', async () => {
+ test('removing hash from links', () => {
element.content = 'hash:foo';
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.isTrue(linkEl.href.endsWith('/awesomesauce'));
assert.equal(linkEl.textContent, 'foo');
});
- test('html with base url', async () => {
+ test('html with base url', () => {
window.CANONICAL_PATH = '/r';
element.content = 'test foo';
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.isTrue(linkEl.href.endsWith('/r/awesomesauce'));
assert.equal(linkEl.textContent, 'foo');
});
- test('a is not at start', async () => {
+ test('a is not at start', () => {
window.CANONICAL_PATH = '/r';
element.content = 'a test foo';
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[1] as HTMLAnchorElement;
assert.isTrue(linkEl.href.endsWith('/r/awesomesauce'));
assert.equal(linkEl.textContent, 'foo');
});
- test('hash html with base url', async () => {
+ test('hash html with base url', () => {
window.CANONICAL_PATH = '/r';
element.content = 'hash:foo';
- await flush();
const linkEl = queryAndAssert(element, '#output')
.childNodes[0] as HTMLAnchorElement;
assert.isTrue(linkEl.href.endsWith('/r/awesomesauce'));
assert.equal(linkEl.textContent, 'foo');
});
- test('disabled config', async () => {
+ test('disabled config', () => {
element.content = 'foo:baz';
- await flush();
assert.equal(queryAndAssert(element, '#output').innerHTML, 'foo:baz');
});
- test('R=email labels link correctly', async () => {
+ test('R=email labels link correctly', () => {
element.removeZeroWidthSpace = true;
element.content = 'R=\u200Btest@google.com';
- await flush();
assert.equal(
queryAndAssert(element, '#output').textContent,
'R=test@google.com'
@@ -296,10 +285,9 @@
);
});
- test('CC=email labels link correctly', async () => {
+ test('CC=email labels link correctly', () => {
element.removeZeroWidthSpace = true;
element.content = 'CC=\u200Btest@google.com';
- await flush();
assert.equal(
queryAndAssert(element, '#output').textContent,
'CC=test@google.com'
@@ -310,42 +298,36 @@
);
});
- test('only {http,https,mailto} protocols are linkified', async () => {
+ test('only {http,https,mailto} protocols are linkified', () => {
element.content = 'xx mailto:test@google.com yy';
- await flush();
let links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 1);
assert.equal(links[0].getAttribute('href'), 'mailto:test@google.com');
assert.equal(links[0].innerHTML, 'mailto:test@google.com');
element.content = 'xx http://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 1);
assert.equal(links[0].getAttribute('href'), 'http://google.com');
assert.equal(links[0].innerHTML, 'http://google.com');
element.content = 'xx https://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 1);
assert.equal(links[0].getAttribute('href'), 'https://google.com');
assert.equal(links[0].innerHTML, 'https://google.com');
element.content = 'xx ssh://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 0);
element.content = 'xx ftp://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 0);
});
- test('links without leading whitespace are linkified', async () => {
+ test('links without leading whitespace are linkified', () => {
element.content = 'xx abcmailto:test@google.com yy';
- await flush();
assert.equal(
queryAndAssert(element, '#output').innerHTML.substr(0, 6),
'xx abc'
@@ -356,7 +338,6 @@
assert.equal(links[0].innerHTML, 'mailto:test@google.com');
element.content = 'xx defhttp://google.com yy';
- await flush();
assert.equal(
queryAndAssert(element, '#output').innerHTML.substr(0, 6),
'xx def'
@@ -367,7 +348,6 @@
assert.equal(links[0].innerHTML, 'http://google.com');
element.content = 'xx qwehttps://google.com yy';
- await flush();
assert.equal(
queryAndAssert(element, '#output').innerHTML.substr(0, 6),
'xx qwe'
@@ -379,7 +359,6 @@
// Non-latin character
element.content = 'xx абвhttps://google.com yy';
- await flush();
assert.equal(
queryAndAssert(element, '#output').innerHTML.substr(0, 6),
'xx абв'
@@ -390,17 +369,15 @@
assert.equal(links[0].innerHTML, 'https://google.com');
element.content = 'xx ssh://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 0);
element.content = 'xx ftp://google.com yy';
- await flush();
links = queryAndAssert(element, '#output').querySelectorAll('a');
assert.equal(links.length, 0);
});
- test('overlapping links', async () => {
+ test('overlapping links', () => {
element.config = {
b1: {
match: '(B:\\s*)(\\d+)',
@@ -412,8 +389,7 @@
},
};
element.content = '- B: 123, 45';
- await flush();
- const links = element.shadowRoot!.querySelectorAll('a');
+ const links = element.root!.querySelectorAll('a');
assert.equal(links.length, 2);
assert.equal(
@@ -427,4 +403,12 @@
assert.equal(links[1].href, 'ftp://foo/45');
assert.equal(links[1].textContent, '45');
});
+
+ test('_contentOrConfigChanged called with config', () => {
+ const contentStub = sinon.stub(element, '_contentChanged');
+ const contentConfigStub = sinon.stub(element, '_contentOrConfigChanged');
+ element.content = 'some text';
+ assert.isTrue(contentStub.called);
+ assert.isTrue(contentConfigStub.called);
+ });
});
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
index b6cb8f9..1622365 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.ts
@@ -34,11 +34,14 @@
}
}
-@customElement('gr-overlay')
-export class GrOverlay extends IronOverlayMixin(
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = IronOverlayMixin(
PolymerElement,
IronOverlayBehavior as IronOverlayBehavior
-) {
+);
+
+@customElement('gr-overlay')
+export class GrOverlay extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
index b2477dd..423a1a8 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.ts
@@ -53,7 +53,7 @@
this.bodyScrollHandler = () => this._handleBodyScroll();
}
- connectedCallback() {
+ override connectedCallback() {
super.connectedCallback();
window.addEventListener('scroll', this.bodyScrollHandler);
}
diff --git a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
index 5b42318..7ed000b 100644
--- a/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
+++ b/polygerrit-ui/app/elements/shared/gr-shell-command/gr-shell-command.ts
@@ -18,8 +18,8 @@
import {GrCopyClipboard} from '../gr-copy-clipboard/gr-copy-clipboard';
import {queryAndAssert} from '../../../utils/common-util';
import {sharedStyles} from '../../../styles/shared-styles';
-import {GrLitElement} from '../../lit/gr-lit-element';
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
declare global {
interface HTMLElementTagNameMap {
@@ -28,7 +28,7 @@
}
@customElement('gr-shell-command')
-export class GrShellCommand extends GrLitElement {
+export class GrShellCommand extends LitElement {
@property({type: String})
command: string | undefined;
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 3d5cb3d..ce1eec3 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -85,8 +85,11 @@
}
}
+// This avoids JSC_DYNAMIC_EXTENDS_WITHOUT_JSDOC closure compiler error.
+const base = KeyboardShortcutMixin(PolymerElement);
+
@customElement('gr-textarea')
-export class GrTextarea extends KeyboardShortcutMixin(PolymerElement) {
+export class GrTextarea extends base {
static get template() {
return htmlTemplate;
}
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
index feed8a6..2b9a868 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content.ts
@@ -15,10 +15,13 @@
* limitations under the License.
*/
import '../gr-icons/gr-icons';
-import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {htmlTemplate} from './gr-tooltip-content_html';
-import {TooltipMixin} from '../../../mixins/gr-tooltip-mixin/gr-tooltip-mixin';
-import {customElement, property} from '@polymer/decorators';
+import '../gr-tooltip/gr-tooltip';
+import {getRootElement} from '../../../scripts/rootElement';
+import {GrTooltip} from '../gr-tooltip/gr-tooltip';
+import {css, html, LitElement, PropertyValues} from 'lit';
+import {customElement, property, state} from 'lit/decorators';
+
+const BOTTOM_OFFSET = 7.2; // Height of the arrow in tooltip.
declare global {
interface HTMLElementTagNameMap {
@@ -26,18 +29,202 @@
}
}
-/**
- * Transclude anything inside and wrap them to support tooltip functionality.
- */
@customElement('gr-tooltip-content')
-export class GrTooltipContent extends TooltipMixin(PolymerElement) {
- static get template() {
- return htmlTemplate;
- }
+export class GrTooltipContent extends LitElement {
+ @property({type: Boolean, attribute: 'has-tooltip', reflect: true})
+ hasTooltip = false;
- @property({type: String, reflectToAttribute: true})
+ @property({type: Boolean, attribute: 'position-below', reflect: true})
+ positionBelow = false;
+
+ @property({type: String, attribute: 'max-width', reflect: true})
maxWidth?: string;
@property({type: Boolean})
showIcon = false;
+
+ // Should be private but used in tests.
+ @state()
+ isTouchDevice = 'ontouchstart' in document.documentElement;
+
+ // Should be private but used in tests.
+ tooltip: GrTooltip | null = null;
+
+ @state()
+ private originalTitle = '';
+
+ private hasSetupTooltipListeners = false;
+
+ private readonly windowScrollHandler: () => void;
+
+ private readonly showHandler: () => void;
+
+ private readonly hideHandler: (e: Event) => void;
+
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
+ constructor() {
+ super();
+ this.windowScrollHandler = () => this._handleWindowScroll();
+ this.showHandler = () => this._handleShowTooltip();
+ this.hideHandler = (e: Event | undefined) => this._handleHideTooltip(e);
+ }
+
+ override disconnectedCallback() {
+ this._handleHideTooltip(undefined);
+ this.removeEventListener('mouseenter', this.showHandler);
+ window.removeEventListener('scroll', this.windowScrollHandler);
+ super.disconnectedCallback();
+ }
+
+ static override get styles() {
+ return [
+ css`
+ iron-icon {
+ width: var(--line-height-normal);
+ height: var(--line-height-normal);
+ vertical-align: top;
+ }
+ `,
+ ];
+ }
+
+ override render() {
+ return html`
+ <slot></slot>
+ ${this.renderIcon()}
+ `;
+ }
+
+ renderIcon() {
+ if (!this.showIcon) return;
+ return html`<iron-icon icon="gr-icons:info"></iron-icon>`;
+ }
+
+ override updated(changedProperties: PropertyValues) {
+ if (changedProperties.has('hasTooltip')) {
+ this.setupTooltipListeners();
+ }
+ }
+
+ private setupTooltipListeners() {
+ if (!this.hasTooltip) {
+ if (this.hasSetupTooltipListeners) {
+ // if attribute set to false, remove the listener
+ this.removeEventListener('mouseenter', this.showHandler);
+ this.hasSetupTooltipListeners = false;
+ }
+ return;
+ }
+
+ if (this.hasSetupTooltipListeners) {
+ return;
+ }
+ this.hasSetupTooltipListeners = true;
+ this.addEventListener('mouseenter', this.showHandler);
+ }
+
+ _handleShowTooltip() {
+ if (this.isTouchDevice) {
+ return;
+ }
+
+ if (
+ !this.hasAttribute('title') ||
+ this.getAttribute('title') === '' ||
+ this.tooltip
+ ) {
+ return;
+ }
+
+ // Store the title attribute text then set it to an empty string to
+ // prevent it from showing natively.
+ this.originalTitle = this.getAttribute('title') || '';
+ this.setAttribute('title', '');
+
+ const tooltip = document.createElement('gr-tooltip');
+ tooltip.text = this.originalTitle;
+ tooltip.maxWidth = this.getAttribute('max-width') || '';
+ tooltip.positionBelow = this.hasAttribute('position-below');
+
+ // Set visibility to hidden before appending to the DOM so that
+ // calculations can be made based on the element’s size.
+ tooltip.style.visibility = 'hidden';
+ getRootElement().appendChild(tooltip);
+ this._positionTooltip(tooltip);
+ tooltip.style.visibility = 'initial';
+
+ this.tooltip = tooltip;
+ window.addEventListener('scroll', this.windowScrollHandler);
+ this.addEventListener('mouseleave', this.hideHandler);
+ this.addEventListener('click', this.hideHandler);
+ tooltip.addEventListener('mouseleave', this.hideHandler);
+ }
+
+ _handleHideTooltip(e: Event | undefined) {
+ if (this.isTouchDevice) {
+ return;
+ }
+ if (!this.hasAttribute('title') || !this.originalTitle) {
+ return;
+ }
+ // Do not hide if mouse left this or this.tooltip and came to this or
+ // this.tooltip
+ if (
+ (e as MouseEvent)?.relatedTarget === this.tooltip ||
+ (e as MouseEvent)?.relatedTarget === this
+ ) {
+ return;
+ }
+
+ window.removeEventListener('scroll', this.windowScrollHandler);
+ this.removeEventListener('mouseleave', this.hideHandler);
+ this.removeEventListener('click', this.hideHandler);
+ this.setAttribute('title', this.originalTitle);
+ this.tooltip?.removeEventListener('mouseleave', this.hideHandler);
+
+ if (this.tooltip?.parentNode) {
+ this.tooltip.parentNode.removeChild(this.tooltip);
+ }
+ this.tooltip = null;
+ }
+
+ _handleWindowScroll() {
+ if (!this.tooltip) {
+ return;
+ }
+ // This wait is needed for tooltips to be positioned correctly in Firefox
+ // and Safari.
+ this.updateComplete.then(() => this._positionTooltip(this.tooltip));
+ }
+
+ // private but used in tests.
+ async _positionTooltip(tooltip: GrTooltip | null) {
+ if (tooltip === null) return;
+ const rect = this.getBoundingClientRect();
+ const boxRect = tooltip.getBoundingClientRect();
+ if (!tooltip.parentElement) {
+ return;
+ }
+ const parentRect = tooltip.parentElement.getBoundingClientRect();
+ const top = rect.top - parentRect.top;
+ const left = rect.left - parentRect.left + (rect.width - boxRect.width) / 2;
+ const right = parentRect.width - left - boxRect.width;
+ if (left < 0) {
+ tooltip.updateStyles({
+ '--gr-tooltip-arrow-center-offset': `${left}px`,
+ });
+ } else if (right < 0) {
+ tooltip.updateStyles({
+ '--gr-tooltip-arrow-center-offset': `${-0.5 * right}px`,
+ });
+ }
+ tooltip.style.left = `${Math.max(0, left)}px`;
+
+ if (!this.positionBelow) {
+ tooltip.style.top = `${Math.max(0, top)}px`;
+ tooltip.style.transform = `translateY(calc(-100% - ${BOTTOM_OFFSET}px))`;
+ } else {
+ tooltip.style.top = `${top + rect.height + BOTTOM_OFFSET}px`;
+ }
+ }
}
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_html.ts b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_html.ts
deleted file mode 100644
index 952420d..0000000
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_html.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import {html} from '@polymer/polymer/lib/utils/html-tag';
-
-export const htmlTemplate = html`
- <style>
- iron-icon {
- width: var(--line-height-normal);
- height: var(--line-height-normal);
- vertical-align: top;
- }
- </style>
- <slot></slot
- ><!--
- --><iron-icon icon="gr-icons:info" hidden$="[[!showIcon]]"></iron-icon>
-`;
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.js b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.js
index f905eaa..8d3bbb0 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip-content/gr-tooltip-content_test.js
@@ -17,35 +17,162 @@
import '../../../test/common-test-setup-karma.js';
import './gr-tooltip-content.js';
-import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-const basicFixture = fixtureFromTemplate(html`
-<gr-tooltip-content>
- </gr-tooltip-content>
-`);
+const basicFixture = fixtureFromElement('gr-tooltip-content');
suite('gr-tooltip-content tests', () => {
let element;
- setup(() => {
+
+ function makeTooltip(tooltipRect, parentRect) {
+ return {
+ getBoundingClientRect() { return tooltipRect; },
+ updateStyles: sinon.stub(),
+ style: {left: 0, top: 0},
+ parentElement: {
+ getBoundingClientRect() { return parentRect; },
+ },
+ };
+ }
+
+ setup(async () => {
element = basicFixture.instantiate();
+ element.title = 'title';
+ await element.updateComplete;
});
test('icon is not visible by default', () => {
- assert.equal(dom(element.root)
- .querySelector('iron-icon').hidden, true);
+ assert.isNotOk(element.shadowRoot.querySelector('iron-icon'));
});
- test('position-below attribute is reflected', () => {
+ test('icon is visible with showIcon property', async () => {
+ element.showIcon = true;
+ await element.updateComplete;
+ assert.isOk(element.shadowRoot.querySelector('iron-icon'));
+ });
+
+ test('position-below attribute is reflected', async () => {
assert.isFalse(element.hasAttribute('position-below'));
element.positionBelow = true;
+ await element.updateComplete;
assert.isTrue(element.hasAttribute('position-below'));
});
- test('icon is visible with showIcon property', () => {
- element.showIcon = true;
- assert.equal(dom(element.root)
- .querySelector('iron-icon').hidden, false);
+ test('normal position', () => {
+ sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
+ return {top: 100, left: 100, width: 200};
+ });
+ const tooltip = makeTooltip(
+ {height: 30, width: 50},
+ {top: 0, left: 0, width: 1000});
+
+ element._positionTooltip(tooltip);
+ assert.isFalse(tooltip.updateStyles.called);
+ assert.equal(tooltip.style.left, '175px');
+ assert.equal(tooltip.style.top, '100px');
+ });
+
+ test('left side position', () => {
+ sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
+ return {top: 100, left: 10, width: 50};
+ });
+ const tooltip = makeTooltip(
+ {height: 30, width: 120},
+ {top: 0, left: 0, width: 1000});
+
+ element._positionTooltip(tooltip);
+ assert.isTrue(tooltip.updateStyles.called);
+ const offset = tooltip.updateStyles
+ .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
+ assert.isBelow(parseFloat(offset.replace(/px$/, '')), 0);
+ assert.equal(tooltip.style.left, '0px');
+ assert.equal(tooltip.style.top, '100px');
+ });
+
+ test('right side position', () => {
+ sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
+ return {top: 100, left: 950, width: 50};
+ });
+ const tooltip = makeTooltip(
+ {height: 30, width: 120},
+ {top: 0, left: 0, width: 1000});
+
+ element._positionTooltip(tooltip);
+ assert.isTrue(tooltip.updateStyles.called);
+ const offset = tooltip.updateStyles
+ .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
+ assert.isAbove(parseFloat(offset.replace(/px$/, '')), 0);
+ assert.equal(tooltip.style.left, '915px');
+ assert.equal(tooltip.style.top, '100px');
+ });
+
+ test('position to bottom', () => {
+ sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
+ return {top: 100, left: 950, width: 50, height: 50};
+ });
+ const tooltip = makeTooltip(
+ {height: 30, width: 120},
+ {top: 0, left: 0, width: 1000});
+
+ element.positionBelow = true;
+ element._positionTooltip(tooltip);
+ assert.isTrue(tooltip.updateStyles.called);
+ const offset = tooltip.updateStyles
+ .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
+ assert.isAbove(parseFloat(offset.replace(/px$/, '')), 0);
+ assert.equal(tooltip.style.left, '915px');
+ assert.equal(tooltip.style.top, '157.2px');
+ });
+
+ test('hides tooltip when detached', async () => {
+ sinon.stub(element, '_handleHideTooltip');
+ element.remove();
+ await element.updateComplete;
+ assert.isTrue(element._handleHideTooltip.called);
+ });
+
+ test('sets up listeners when has-tooltip is changed', async () => {
+ const addListenerStub = sinon.stub(element, 'addEventListener');
+ element.hasTooltip = true;
+ await element.updateComplete;
+ assert.isTrue(addListenerStub.called);
+ });
+
+ test('clean up listeners when has-tooltip changed to false', async () => {
+ const removeListenerStub = sinon.stub(element, 'removeEventListener');
+ element.hasTooltip = true;
+ await element.updateComplete;
+ element.hasTooltip = false;
+ await element.updateComplete;
+ assert.isTrue(removeListenerStub.called);
+ });
+
+ test('do not display tooltips on touch devices', async () => {
+ // On touch devices, tooltips should not be shown.
+ element.isTouchDevice = true;
+ await element.updateComplete;
+
+ // fire mouse-enter
+ element._handleShowTooltip();
+ await element.updateComplete;
+ assert.isNotOk(element.tooltip);
+
+ // fire mouse-enter
+ element._handleHideTooltip();
+ await element.updateComplete;
+ assert.isNotOk(element.tooltip);
+
+ // On other devices, tooltips should be shown.
+ element.isTouchDevice = false;
+
+ // fire mouse-enter
+ element._handleShowTooltip();
+ await element.updateComplete;
+ assert.isOk(element.tooltip);
+
+ // fire mouse-enter
+ element._handleHideTooltip();
+ await element.updateComplete;
+ assert.isNotOk(element.tooltip);
});
});
diff --git a/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts b/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
index 789637c..2fd3fb9 100644
--- a/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-vote-chip/gr-vote-chip.ts
@@ -14,12 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css, customElement, html, property} from 'lit-element';
+import {LitElement, css, html} from 'lit';
+import {customElement, property} from 'lit/decorators';
import {ApprovalInfo, LabelInfo} from '../../../api/rest-api';
import {appContext} from '../../../services/app-context';
import {KnownExperimentId} from '../../../services/flags/flags';
-import {getVotingRangeOrDefault, valueString} from '../../../utils/label-util';
-import {GrLitElement} from '../../lit/gr-lit-element';
+import {
+ classForLabelStatus,
+ getLabelStatus,
+ valueString,
+} from '../../../utils/label-util';
declare global {
interface HTMLElementTagNameMap {
@@ -28,73 +32,99 @@
}
@customElement('gr-vote-chip')
-export class GrVoteChip extends GrLitElement {
+export class GrVoteChip extends LitElement {
@property({type: Object})
vote?: ApprovalInfo;
@property({type: Object})
label?: LabelInfo;
+ /** Show vote as a stack of same votes. */
+ @property({type: Boolean})
+ more = false;
+
private readonly flagsService = appContext.flagsService;
- static get styles() {
+ static override get styles() {
return [
css`
- .chipVote {
- display: flex;
- justify-content: center;
- margin-right: var(--spacing-s);
- padding: 1px;
- border-radius: var(--border-radius);
- color: var(--vote-text-color);
- border: 1px solid var(--border-color);
- line-height: calc(var(--line-height-normal) - 4px);
- }
- .max {
+ .vote-chip.max {
background-color: var(--vote-color-approved);
+ padding: 2px;
}
- .min {
+ .vote-chip.max.more {
+ padding: 1px;
+ border: 1px solid var(--vote-outline-recommended);
+ }
+ .vote-chip.min {
background-color: var(--vote-color-rejected);
+ padding: 2px;
}
- .positive {
+ .vote-chip.min.more {
+ padding: 1px;
+ border: 1px solid var(--vote-outline-disliked);
+ }
+ .vote-chip.positive,
+ .chip-angle.max,
+ .chip-angle.positive {
background-color: var(--vote-color-recommended);
border: 1px solid var(--vote-outline-recommended);
color: var(--chip-color);
}
- .negative {
+ .vote-chip.negative,
+ .chip-angle.min,
+ .chip-angle.negative {
background-color: var(--vote-color-disliked);
border: 1px solid var(--vote-outline-disliked);
color: var(--chip-color);
}
+ .vote-chip,
+ .chip-angle {
+ display: flex;
+ width: var(--gr-vote-chip-width, 16px);
+ height: var(--gr-vote-chip-height, 16px);
+ justify-content: center;
+ margin-right: var(--spacing-s);
+ padding: 1px;
+ border-radius: var(--border-radius);
+ line-height: var(--gr-vote-chip-width, 16px);
+ }
+ .vote-chip {
+ position: relative;
+ z-index: 2;
+ }
+ .chip-angle {
+ position: absolute;
+ top: 2px;
+ left: 2px;
+ z-index: 1;
+ }
+ .container {
+ position: relative;
+ }
`,
];
}
- render() {
+ override render() {
if (!this.flagsService.isEnabled(KnownExperimentId.SUBMIT_REQUIREMENTS_UI))
return;
if (!this.vote?.value) return;
const className = this.computeClass(this.vote.value, this.label);
- return html`<div class="chipVote ${className}">
- ${valueString(this.vote.value)}
- </div>`;
+ return html`<span class="container">
+ <div class="vote-chip ${className} ${this.more ? 'more' : ''}">
+ ${valueString(this.vote.value)}
+ </div>
+ ${this.more
+ ? html`<div class="chip-angle ${className}">
+ ${valueString(this.vote.value)}
+ </div>`
+ : ''}
+ </span>`;
}
- computeClass(vote: Number, label?: LabelInfo) {
- const votingRange = getVotingRangeOrDefault(label);
- if (vote > 0) {
- if (vote === votingRange.max) {
- return 'max';
- } else {
- return 'positive';
- }
- } else if (vote < 0) {
- if (vote === votingRange.min) {
- return 'min';
- } else {
- return 'negative';
- }
- }
- return '';
+ computeClass(vote: number, label?: LabelInfo) {
+ const status = getLabelStatus(label, vote);
+ return classForLabelStatus(status);
}
}
diff --git a/polygerrit-ui/app/empty_test.sh b/polygerrit-ui/app/empty_test.sh
deleted file mode 100755
index e69de29..0000000
--- a/polygerrit-ui/app/empty_test.sh
+++ /dev/null
diff --git a/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin.ts b/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin.ts
deleted file mode 100644
index e3b75de..0000000
--- a/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 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 {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
-import {PolymerElement} from '@polymer/polymer';
-import {Constructor} from '../../utils/common-util';
-import {property} from '@polymer/decorators';
-import {ServerInfo} from '../../types/common';
-
-/**
- * @polymer
- * @mixinFunction
- */
-export const ChangeTableMixin = dedupingMixin(
- <T extends Constructor<PolymerElement>>(
- superClass: T
- ): T & Constructor<ChangeTableMixinInterface> => {
- /**
- * @polymer
- * @mixinClass
- */
- class Mixin extends superClass {
- @property({type: Array})
- readonly columnNames: string[] = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Reviewers',
- 'Comments',
- 'Repo',
- 'Branch',
- 'Updated',
- 'Size',
- ];
-
- isColumnHidden(columnToCheck?: string, columnsToDisplay?: string[]) {
- if (!columnsToDisplay || !columnToCheck) {
- return false;
- }
- return !columnsToDisplay.includes(columnToCheck);
- }
-
- /**
- * Is the column disabled by a server config or experiment? For example the
- * assignee feature might be disabled and thus the corresponding column is
- * also disabled.
- *
- */
- isColumnEnabled(
- column: string,
- config: ServerInfo,
- experiments: string[]
- ) {
- if (!config || !config.change) return true;
- if (column === 'Assignee') return !!config.change.enable_assignee;
- if (column === 'Comments')
- return experiments.includes('comments-column');
- return true;
- }
-
- /**
- * @return enabled columns, see isColumnEnabled().
- */
- getEnabledColumns(
- columns: string[],
- config: ServerInfo,
- experiments: string[]
- ) {
- return columns.filter(col =>
- this.isColumnEnabled(col, config, experiments)
- );
- }
-
- /**
- * The Project column was renamed to Repo, but some users may have
- * preferences that use its old name. If that column is found, rename it
- * before use.
- *
- * @return If the column was renamed, returns a new array
- * with the corrected name. Otherwise, it returns the original param.
- */
- renameProjectToRepoColumn(columns: string[]) {
- const projectIndex = columns.indexOf('Project');
- if (projectIndex === -1) {
- return columns;
- }
- const newColumns = [...columns];
- newColumns[projectIndex] = 'Repo';
- return newColumns;
- }
- }
-
- return Mixin;
- }
-);
-
-export interface ChangeTableMixinInterface {
- readonly columnNames: string[];
- isColumnHidden(columnToCheck?: string, columnsToDisplay?: string[]): boolean;
- isColumnEnabled(
- column: string,
- config: ServerInfo,
- experiments: string[]
- ): boolean;
- getEnabledColumns(
- columns: string[],
- config: ServerInfo,
- experiments: string[]
- ): string[];
- renameProjectToRepoColumn(columns: string[]): string[];
-}
diff --git a/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin_test.js b/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin_test.js
deleted file mode 100644
index 0d6b4ad..0000000
--- a/polygerrit-ui/app/mixins/gr-change-table-mixin/gr-change-table-mixin_test.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 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 '../../test/common-test-setup-karma.js';
-import {ChangeTableMixin} from './gr-change-table-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-
-class GrChangeTableMixinTestElement extends
- ChangeTableMixin(PolymerElement) {
- static get is() { return 'gr-change-table-mixin-test-element'; }
-}
-
-customElements.define(GrChangeTableMixinTestElement.is,
- GrChangeTableMixinTestElement);
-
-const basicFixture = fixtureFromElement(
- 'gr-change-table-mixin-test-element');
-
-suite('gr-change-table-mixin tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('isColumnHidden', () => {
- const columnToCheck = 'Repo';
- let columnsToDisplay = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Repo',
- 'Branch',
- 'Updated',
- 'Size',
- ];
- assert.isFalse(element.isColumnHidden(columnToCheck, columnsToDisplay));
-
- columnsToDisplay = [
- 'Subject',
- 'Status',
- 'Owner',
- 'Assignee',
- 'Branch',
- 'Updated',
- 'Size',
- ];
- assert.isTrue(element.isColumnHidden(columnToCheck, columnsToDisplay));
- });
-
- test('renameProjectToRepoColumn maps Project to Repo', () => {
- const columns = [
- 'Subject',
- 'Status',
- 'Owner',
- ];
- assert.deepEqual(element.renameProjectToRepoColumn(columns),
- columns.slice(0));
- assert.deepEqual(
- element.renameProjectToRepoColumn(columns.concat(['Project'])),
- columns.slice(0).concat(['Repo']));
- });
-});
-
diff --git a/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin.ts b/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin.ts
deleted file mode 100644
index af89194..0000000
--- a/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 {encodeURL, getBaseUrl} from '../../utils/url-util';
-import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
-import {PolymerElement} from '@polymer/polymer';
-import {Constructor} from '../../utils/common-util';
-
-/**
- * @polymer
- * @mixinFunction
- */
-export const ListViewMixin = dedupingMixin(
- <T extends Constructor<PolymerElement>>(
- superClass: T
- ): T & Constructor<ListViewMixinInterface> => {
- /**
- * @polymer
- * @mixinClass
- */
- class Mixin extends superClass {
- computeLoadingClass(loading: boolean): string {
- return loading ? 'loading' : '';
- }
-
- computeShownItems<T>(items: T[]): T[] {
- return items.slice(0, 25);
- }
-
- getUrl(path: string, item: string) {
- return getBaseUrl() + path + encodeURL(item, true);
- }
-
- getFilterValue<T extends ListViewParams>(params: T): string {
- if (!params) {
- return '';
- }
- return params.filter || '';
- }
-
- getOffsetValue<T extends ListViewParams>(params: T): number {
- if (params?.offset) {
- return Number(params.offset);
- }
- return 0;
- }
- }
-
- return Mixin;
- }
-);
-
-export interface ListViewMixinInterface {
- computeLoadingClass(loading: boolean): string;
- computeShownItems<T>(items: T[]): T[];
- getUrl(path: string, item: string): string;
- getFilterValue<T extends ListViewParams>(params: T): string;
- getOffsetValue<T extends ListViewParams>(params: T): number;
-}
-
-export interface ListViewParams {
- filter?: string | null;
- offset?: number | string;
-}
diff --git a/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin_test.js b/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin_test.js
deleted file mode 100644
index 407f29f..0000000
--- a/polygerrit-ui/app/mixins/gr-list-view-mixin/gr-list-view-mixin_test.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 '../../test/common-test-setup-karma.js';
-import {ListViewMixin} from './gr-list-view-mixin.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-
-const basicFixture = fixtureFromElement(
- 'gr-list-view-mixin-test-element');
-
-class GrListViewMixinTestElement extends
- ListViewMixin(PolymerElement) {
- static get is() { return 'gr-list-view-mixin-test-element'; }
-}
-
-customElements.define(GrListViewMixinTestElement.is,
- GrListViewMixinTestElement);
-
-suite('gr-list-view-mixin tests', () => {
- let element;
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('computeLoadingClass', () => {
- assert.equal(element.computeLoadingClass(true), 'loading');
- assert.equal(element.computeLoadingClass(false), '');
- });
-
- test('computeShownItems', () => {
- const myArr = new Array(26);
- assert.equal(element.computeShownItems(myArr).length, 25);
- });
-
- test('getUrl', () => {
- assert.equal(element.getUrl('/path/to/something/', 'item'),
- '/path/to/something/item');
- assert.equal(element.getUrl('/path/to/something/', 'item%test'),
- '/path/to/something/item%2525test');
- });
-
- test('getFilterValue', () => {
- let params;
- assert.equal(element.getFilterValue(params), '');
-
- params = {filter: null};
- assert.equal(element.getFilterValue(params), '');
-
- params = {filter: 'test'};
- assert.equal(element.getFilterValue(params), 'test');
- });
-
- test('getOffsetValue', () => {
- let params;
- assert.equal(element.getOffsetValue(params), 0);
-
- params = {offset: null};
- assert.equal(element.getOffsetValue(params), 0);
-
- params = {offset: 1};
- assert.equal(element.getOffsetValue(params), 1);
- });
-});
-
diff --git a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts b/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts
deleted file mode 100644
index 4d119eb..0000000
--- a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * @license
- * Copyright (C) 2016 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 '../../elements/shared/gr-tooltip/gr-tooltip';
-import {flush} from '@polymer/polymer/lib/legacy/polymer.dom';
-import {getRootElement} from '../../scripts/rootElement';
-import {property, observe} from '@polymer/decorators';
-import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
-import {GrTooltip} from '../../elements/shared/gr-tooltip/gr-tooltip';
-import {PolymerElement} from '@polymer/polymer';
-import {Constructor} from '../../utils/common-util';
-
-const BOTTOM_OFFSET = 7.2; // Height of the arrow in tooltip.
-
-/** The interface corresponding to TooltipMixin */
-export interface TooltipMixinInterface {
- hasTooltip: boolean;
- positionBelow: boolean;
- _isTouchDevice: boolean;
- _tooltip: GrTooltip | null;
- _titleText: string;
- _hasSetupTooltipListeners: boolean;
-}
-
-/**
- * @polymer
- * @mixinFunction
- */
-export const TooltipMixin = dedupingMixin(
- <T extends Constructor<PolymerElement>>(
- superClass: T
- ): T & Constructor<TooltipMixinInterface> => {
- /**
- * @polymer
- * @mixinClass
- */
- class Mixin extends superClass {
- @property({type: Boolean})
- hasTooltip = false;
-
- @property({type: Boolean, reflectToAttribute: true})
- positionBelow = false;
-
- @property({type: Boolean})
- _isTouchDevice = 'ontouchstart' in document.documentElement;
-
- @property({type: Object})
- _tooltip: GrTooltip | null = null;
-
- @property({type: String})
- _titleText = '';
-
- @property({type: Boolean})
- _hasSetupTooltipListeners = false;
-
- // Handler for mouseenter event
- private mouseenterHandler?: (e: MouseEvent) => void;
-
- // Handler for scrolling on window
- private readonly windowScrollHandler: () => void;
-
- // Handler for showing the tooltip, will be attached to certain events
- private readonly showHandler: () => void;
-
- // Handler for hiding the tooltip, will be attached to certain events
- private readonly hideHandler: (e: Event) => void;
-
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any
- constructor(..._: any[]) {
- super();
- this.windowScrollHandler = () => this._handleWindowScroll();
- this.showHandler = () => this._handleShowTooltip();
- this.hideHandler = (e: Event | undefined) => this._handleHideTooltip(e);
- }
-
- override disconnectedCallback() {
- // NOTE: if you define your own `detached` in your component
- // then this won't take affect (as its not a class yet)
- this._handleHideTooltip(undefined);
- if (this.mouseenterHandler) {
- this.removeEventListener('mouseenter', this.mouseenterHandler);
- }
- window.removeEventListener('scroll', this.windowScrollHandler);
- super.disconnectedCallback();
- }
-
- @observe('hasTooltip')
- _setupTooltipListeners() {
- if (!this.mouseenterHandler) {
- this.mouseenterHandler = this.showHandler;
- }
-
- if (!this.hasTooltip) {
- // if attribute set to false, remove the listener
- this.removeEventListener('mouseenter', this.mouseenterHandler);
- this._hasSetupTooltipListeners = false;
- return;
- }
-
- if (this._hasSetupTooltipListeners) {
- return;
- }
- this._hasSetupTooltipListeners = true;
-
- this.addEventListener('mouseenter', this.mouseenterHandler);
- }
-
- _handleShowTooltip() {
- if (this._isTouchDevice) {
- return;
- }
-
- if (
- !this.hasAttribute('title') ||
- this.getAttribute('title') === '' ||
- this._tooltip
- ) {
- return;
- }
-
- // Store the title attribute text then set it to an empty string to
- // prevent it from showing natively.
- this._titleText = this.getAttribute('title') || '';
- this.setAttribute('title', '');
-
- const tooltip = document.createElement('gr-tooltip');
- tooltip.text = this._titleText;
- tooltip.maxWidth = this.getAttribute('max-width') || '';
- tooltip.positionBelow = this.hasAttribute('position-below');
-
- // Set visibility to hidden before appending to the DOM so that
- // calculations can be made based on the element’s size.
- tooltip.style.visibility = 'hidden';
- getRootElement().appendChild(tooltip);
- this._positionTooltip(tooltip);
- tooltip.style.visibility = 'initial';
-
- this._tooltip = tooltip;
- window.addEventListener('scroll', this.windowScrollHandler);
- this.addEventListener('mouseleave', this.hideHandler);
- this.addEventListener('click', this.hideHandler);
- tooltip.addEventListener('mouseleave', this.hideHandler);
- }
-
- _handleHideTooltip(e: Event | undefined) {
- if (this._isTouchDevice) {
- return;
- }
- if (!this.hasAttribute('title') || !this._titleText) {
- return;
- }
- // Do not hide if mouse left this or this._tooltip and came to this or
- // this._tooltip
- if (
- (e as MouseEvent)?.relatedTarget === this._tooltip ||
- (e as MouseEvent)?.relatedTarget === this
- ) {
- return;
- }
-
- window.removeEventListener('scroll', this.windowScrollHandler);
- this.removeEventListener('mouseleave', this.hideHandler);
- this.removeEventListener('click', this.hideHandler);
- this.setAttribute('title', this._titleText);
- this._tooltip?.removeEventListener('mouseleave', this.hideHandler);
-
- if (this._tooltip?.parentNode) {
- this._tooltip.parentNode.removeChild(this._tooltip);
- }
- this._tooltip = null;
- }
-
- _handleWindowScroll() {
- if (!this._tooltip) {
- return;
- }
-
- this._positionTooltip(this._tooltip);
- }
-
- _positionTooltip(tooltip: GrTooltip) {
- // This flush is needed for tooltips to be positioned correctly in Firefox
- // and Safari.
- flush();
- const rect = this.getBoundingClientRect();
- const boxRect = tooltip.getBoundingClientRect();
- if (!tooltip.parentElement) {
- return;
- }
- const parentRect = tooltip.parentElement.getBoundingClientRect();
- const top = rect.top - parentRect.top;
- const left =
- rect.left - parentRect.left + (rect.width - boxRect.width) / 2;
- const right = parentRect.width - left - boxRect.width;
- if (left < 0) {
- tooltip.updateStyles({
- '--gr-tooltip-arrow-center-offset': `${left}px`,
- });
- } else if (right < 0) {
- tooltip.updateStyles({
- '--gr-tooltip-arrow-center-offset': `${-0.5 * right}px`,
- });
- }
- tooltip.style.left = `${Math.max(0, left)}px`;
-
- if (!this.positionBelow) {
- tooltip.style.top = `${Math.max(0, top)}px`;
- tooltip.style.transform = `translateY(calc(-100% - ${BOTTOM_OFFSET}px))`;
- } else {
- tooltip.style.top = `${top + rect.height + BOTTOM_OFFSET}px`;
- }
- }
- }
-
- return Mixin;
- }
-);
diff --git a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin_test.js b/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin_test.js
deleted file mode 100644
index 209c83af..0000000
--- a/polygerrit-ui/app/mixins/gr-tooltip-mixin/gr-tooltip-mixin_test.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- * @license
- * Copyright (C) 2017 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 '../../test/common-test-setup-karma.js';
-import {PolymerElement} from '@polymer/polymer/polymer-element.js';
-import {TooltipMixin} from './gr-tooltip-mixin.js';
-
-const basicFixture = fixtureFromElement('gr-tooltip-mixin-element');
-
-class GrTooltipMixinTestElement extends TooltipMixin(PolymerElement) {
- static get is() {
- return 'gr-tooltip-mixin-element';
- }
-}
-
-customElements.define(GrTooltipMixinTestElement.is,
- GrTooltipMixinTestElement);
-
-suite('gr-tooltip-mixin tests', () => {
- let element;
-
- function makeTooltip(tooltipRect, parentRect) {
- return {
- getBoundingClientRect() { return tooltipRect; },
- updateStyles: sinon.stub(),
- style: {left: 0, top: 0},
- parentElement: {
- getBoundingClientRect() { return parentRect; },
- },
- };
- }
-
- setup(() => {
- element = basicFixture.instantiate();
- });
-
- test('normal position', () => {
- sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
- return {top: 100, left: 100, width: 200};
- });
- const tooltip = makeTooltip(
- {height: 30, width: 50},
- {top: 0, left: 0, width: 1000});
-
- element._positionTooltip(tooltip);
- assert.isFalse(tooltip.updateStyles.called);
- assert.equal(tooltip.style.left, '175px');
- assert.equal(tooltip.style.top, '100px');
- });
-
- test('left side position', () => {
- sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
- return {top: 100, left: 10, width: 50};
- });
- const tooltip = makeTooltip(
- {height: 30, width: 120},
- {top: 0, left: 0, width: 1000});
-
- element._positionTooltip(tooltip);
- assert.isTrue(tooltip.updateStyles.called);
- const offset = tooltip.updateStyles
- .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
- assert.isBelow(parseFloat(offset.replace(/px$/, '')), 0);
- assert.equal(tooltip.style.left, '0px');
- assert.equal(tooltip.style.top, '100px');
- });
-
- test('right side position', () => {
- sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
- return {top: 100, left: 950, width: 50};
- });
- const tooltip = makeTooltip(
- {height: 30, width: 120},
- {top: 0, left: 0, width: 1000});
-
- element._positionTooltip(tooltip);
- assert.isTrue(tooltip.updateStyles.called);
- const offset = tooltip.updateStyles
- .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
- assert.isAbove(parseFloat(offset.replace(/px$/, '')), 0);
- assert.equal(tooltip.style.left, '915px');
- assert.equal(tooltip.style.top, '100px');
- });
-
- test('position to bottom', () => {
- sinon.stub(element, 'getBoundingClientRect').callsFake(() => {
- return {top: 100, left: 950, width: 50, height: 50};
- });
- const tooltip = makeTooltip(
- {height: 30, width: 120},
- {top: 0, left: 0, width: 1000});
-
- element.positionBelow = true;
- element._positionTooltip(tooltip);
- assert.isTrue(tooltip.updateStyles.called);
- const offset = tooltip.updateStyles
- .lastCall.args[0]['--gr-tooltip-arrow-center-offset'];
- assert.isAbove(parseFloat(offset.replace(/px$/, '')), 0);
- assert.equal(tooltip.style.left, '915px');
- assert.equal(tooltip.style.top, '157.2px');
- });
-
- test('hides tooltip when detached', () => {
- sinon.stub(element, '_handleHideTooltip');
- element.remove();
- flush();
- assert.isTrue(element._handleHideTooltip.called);
- });
-
- test('sets up listeners when has-tooltip is changed', () => {
- const addListenerStub = sinon.stub(element, 'addEventListener');
- element.hasTooltip = true;
- assert.isTrue(addListenerStub.called);
- });
-
- test('clean up listeners when has-tooltip changed to false', () => {
- const removeListenerStub = sinon.stub(element, 'removeEventListener');
- element.hasTooltip = true;
- element.hasTooltip = false;
- assert.isTrue(removeListenerStub.called);
- });
-});
-
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
index c48b179..9092919 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.ts
@@ -99,7 +99,6 @@
import {IronA11yKeysBehavior} from '@polymer/iron-a11y-keys-behavior/iron-a11y-keys-behavior';
import {dom, EventApi} from '@polymer/polymer/lib/legacy/polymer.dom';
import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class';
-import {dedupingMixin} from '@polymer/polymer/lib/utils/mixin';
import {property} from '@polymer/decorators';
import {PolymerElement} from '@polymer/polymer';
import {check, Constructor} from '../../utils/common-util';
@@ -151,6 +150,8 @@
TOGGLE_CHANGE_REVIEWED = 'TOGGLE_CHANGE_REVIEWED',
TOGGLE_CHANGE_STAR = 'TOGGLE_CHANGE_STAR',
REFRESH_CHANGE_LIST = 'REFRESH_CHANGE_LIST',
+ OPEN_SUBMIT_DIALOG = 'OPEN_SUBMIT_DIALOG',
+ TOGGLE_ATTENTION_SET = 'TOGGLE_ATTENTION_SET',
OPEN_REPLY_DIALOG = 'OPEN_REPLY_DIALOG',
OPEN_DOWNLOAD_DIALOG = 'OPEN_DOWNLOAD_DIALOG',
@@ -329,6 +330,16 @@
ShortcutSection.ACTIONS,
'Star/unstar change'
);
+_describe(
+ Shortcut.OPEN_SUBMIT_DIALOG,
+ ShortcutSection.ACTIONS,
+ 'Open submit dialog'
+);
+_describe(
+ Shortcut.TOGGLE_ATTENTION_SET,
+ ShortcutSection.ACTIONS,
+ 'Toggle attention set status'
+);
_describe(Shortcut.EDIT_TOPIC, ShortcutSection.ACTIONS, 'Add a change topic');
_describe(
Shortcut.DIFF_AGAINST_BASE,
@@ -742,337 +753,335 @@
* @polymer
* @mixinFunction
*/
-const InternalKeyboardShortcutMixin = dedupingMixin(
- <T extends Constructor<PolymerElement> & IronA11yKeysMixinConstructor>(
- superClass: T
- ): T & Constructor<KeyboardShortcutMixinInterface> => {
+const InternalKeyboardShortcutMixin = <
+ T extends Constructor<PolymerElement> & IronA11yKeysMixinConstructor
+>(
+ superClass: T
+) => {
+ /**
+ * @polymer
+ * @mixinClass
+ */
+ class Mixin extends superClass {
+ @property({type: Number})
+ _shortcut_go_key_last_pressed: number | null = null;
+
+ @property({type: Number})
+ _shortcut_v_key_last_pressed: number | null = null;
+
+ @property({type: Object})
+ _shortcut_go_table: Map<string, string> = new Map<string, string>();
+
+ @property({type: Object})
+ _shortcut_v_table: Map<string, string> = new Map<string, string>();
+
+ Shortcut = Shortcut;
+
+ ShortcutSection = ShortcutSection;
+
+ private _disableKeyboardShortcuts = false;
+
+ private readonly restApiService = appContext.restApiService;
+
+ private reporting = appContext.reportingService;
+
+ /** Used to disable shortcuts when the element is not visible. */
+ private observer?: IntersectionObserver;
+
/**
- * @polymer
- * @mixinClass
+ * Enabling shortcuts only when the element is visible (see `observer`
+ * above) is a great feature, but often what you want is for the *page* to
+ * be visible, not the specific child element that registers keyboard
+ * shortcuts. An example is the FileList in the ChangeView. So we allow
+ * a broader observer target to be specified here, and fall back to
+ * `this` as the default.
*/
- class Mixin extends superClass {
- @property({type: Number})
- _shortcut_go_key_last_pressed: number | null = null;
+ @property({type: Object})
+ observerTarget: Element = this;
- @property({type: Number})
- _shortcut_v_key_last_pressed: number | null = null;
+ /** Are shortcuts currently enabled? True only when element is visible. */
+ private bindingsEnabled = false;
- @property({type: Object})
- _shortcut_go_table: Map<string, string> = new Map<string, string>();
-
- @property({type: Object})
- _shortcut_v_table: Map<string, string> = new Map<string, string>();
-
- Shortcut = Shortcut;
-
- ShortcutSection = ShortcutSection;
-
- private _disableKeyboardShortcuts = false;
-
- private readonly restApiService = appContext.restApiService;
-
- private reporting = appContext.reportingService;
-
- /** Used to disable shortcuts when the element is not visible. */
- private observer?: IntersectionObserver;
-
- /**
- * Enabling shortcuts only when the element is visible (see `observer`
- * above) is a great feature, but often what you want is for the *page* to
- * be visible, not the specific child element that registers keyboard
- * shortcuts. An example is the FileList in the ChangeView. So we allow
- * a broader observer target to be specified here, and fall back to
- * `this` as the default.
+ modifierPressed(event: CustomKeyboardEvent) {
+ /* We are checking for g/v as modifiers pressed. There are cases such as
+ * pressing v and then /, where we want the handler for / to be triggered.
+ * TODO(dhruvsri): find a way to support that keyboard combination
*/
- @property({type: Object})
- observerTarget: Element = this;
+ const e = getKeyboardEvent(event);
+ return (
+ isModifierPressed(e) || !!this._inGoKeyMode() || !!this.inVKeyMode()
+ );
+ }
- /** Are shortcuts currently enabled? True only when element is visible. */
- private bindingsEnabled = false;
-
- modifierPressed(event: CustomKeyboardEvent) {
- /* We are checking for g/v as modifiers pressed. There are cases such as
- * pressing v and then /, where we want the handler for / to be triggered.
- * TODO(dhruvsri): find a way to support that keyboard combination
- */
- const e = getKeyboardEvent(event);
- return (
- isModifierPressed(e) || !!this._inGoKeyMode() || !!this.inVKeyMode()
- );
+ shouldSuppressKeyboardShortcut(event: CustomKeyboardEvent) {
+ if (this._disableKeyboardShortcuts) return true;
+ const e = getKeyboardEvent(event);
+ // TODO(TS): maybe override the EventApi, narrow it down to Element always
+ const target = (dom(e) as EventApi).rootTarget as Element;
+ const tagName = target.tagName;
+ const type = target.getAttribute('type');
+ if (
+ // Suppress shortcuts on <input> and <textarea>, but not on
+ // checkboxes, because we want to enable workflows like 'click
+ // mark-reviewed and then press ] to go to the next file'.
+ (tagName === 'INPUT' && type !== 'checkbox') ||
+ tagName === 'TEXTAREA' ||
+ // Suppress shortcuts if the key is 'enter'
+ // and target is an anchor or button or paper-tab.
+ (e.keyCode === 13 &&
+ (tagName === 'A' || tagName === 'BUTTON' || tagName === 'PAPER-TAB'))
+ ) {
+ return true;
}
-
- shouldSuppressKeyboardShortcut(event: CustomKeyboardEvent) {
- if (this._disableKeyboardShortcuts) return true;
- const e = getKeyboardEvent(event);
- // TODO(TS): maybe override the EventApi, narrow it down to Element always
- const target = (dom(e) as EventApi).rootTarget as Element;
- const tagName = target.tagName;
- const type = target.getAttribute('type');
- if (
- // Suppress shortcuts on <input> and <textarea>, but not on
- // checkboxes, because we want to enable workflows like 'click
- // mark-reviewed and then press ] to go to the next file'.
- (tagName === 'INPUT' && type !== 'checkbox') ||
- tagName === 'TEXTAREA' ||
- // Suppress shortcuts if the key is 'enter'
- // and target is an anchor or button or paper-tab.
- (e.keyCode === 13 &&
- (tagName === 'A' ||
- tagName === 'BUTTON' ||
- tagName === 'PAPER-TAB'))
- ) {
+ for (let i = 0; e.path && i < e.path.length; i++) {
+ // TODO(TS): narrow this down to Element from EventTarget first
+ if ((e.path[i] as Element).tagName === 'GR-OVERLAY') {
return true;
}
- for (let i = 0; e.path && i < e.path.length; i++) {
- // TODO(TS): narrow this down to Element from EventTarget first
- if ((e.path[i] as Element).tagName === 'GR-OVERLAY') {
- return true;
- }
- }
-
- // eg: {key: "k:keydown", ..., from: "gr-diff-view"}
- let key = `${(e as unknown as KeyboardEvent).key}:${e.type}`;
- if (this._inGoKeyMode()) key = 'g+' + key;
- if (this.inVKeyMode()) key = 'v+' + key;
- if (e.shiftKey) key = 'shift+' + key;
- if (e.ctrlKey) key = 'ctrl+' + key;
- if (e.metaKey) key = 'meta+' + key;
- if (e.altKey) key = 'alt+' + key;
- this.reporting.reportInteraction('shortcut-triggered', {
- key,
- from: this.nodeName ?? 'unknown',
- });
- return false;
}
- // Alias for getKeyboardEvent.
- getKeyboardEvent(e: CustomKeyboardEvent) {
- return getKeyboardEvent(e);
+ // eg: {key: "k:keydown", ..., from: "gr-diff-view"}
+ let key = `${(e as unknown as KeyboardEvent).key}:${e.type}`;
+ if (this._inGoKeyMode()) key = 'g+' + key;
+ if (this.inVKeyMode()) key = 'v+' + key;
+ if (e.shiftKey) key = 'shift+' + key;
+ if (e.ctrlKey) key = 'ctrl+' + key;
+ if (e.metaKey) key = 'meta+' + key;
+ if (e.altKey) key = 'alt+' + key;
+ this.reporting.reportInteraction('shortcut-triggered', {
+ key,
+ from: this.nodeName ?? 'unknown',
+ });
+ return false;
+ }
+
+ // Alias for getKeyboardEvent.
+ getKeyboardEvent(e: CustomKeyboardEvent) {
+ return getKeyboardEvent(e);
+ }
+
+ bindShortcut(shortcut: Shortcut, ...bindings: string[]) {
+ shortcutManager.bindShortcut(shortcut, ...bindings);
+ }
+
+ createTitle(shortcutName: Shortcut, section: ShortcutSection) {
+ const desc = shortcutManager.getDescription(section, shortcutName);
+ const shortcut = shortcutManager.getShortcut(shortcutName);
+ return desc && shortcut ? `${desc} (shortcut: ${shortcut})` : '';
+ }
+
+ _addOwnKeyBindings(shortcut: Shortcut, handler: string) {
+ const bindings = shortcutManager.getBindingsForShortcut(shortcut);
+ if (!bindings) {
+ return;
}
-
- bindShortcut(shortcut: Shortcut, ...bindings: string[]) {
- shortcutManager.bindShortcut(shortcut, ...bindings);
+ if (bindings[0] === SPECIAL_SHORTCUT.DOC_ONLY) {
+ return;
}
-
- createTitle(shortcutName: Shortcut, section: ShortcutSection) {
- const desc = shortcutManager.getDescription(section, shortcutName);
- const shortcut = shortcutManager.getShortcut(shortcutName);
- return desc && shortcut ? `${desc} (shortcut: ${shortcut})` : '';
- }
-
- _addOwnKeyBindings(shortcut: Shortcut, handler: string) {
- const bindings = shortcutManager.getBindingsForShortcut(shortcut);
- if (!bindings) {
- return;
- }
- if (bindings[0] === SPECIAL_SHORTCUT.DOC_ONLY) {
- return;
- }
- if (bindings[0] === SPECIAL_SHORTCUT.GO_KEY) {
- bindings
- .slice(1)
- .forEach(binding => this._shortcut_go_table.set(binding, handler));
- } else if (bindings[0] === SPECIAL_SHORTCUT.V_KEY) {
- // for each binding added with the go/v key, we set the handler to be
- // handleVKeyAction. handleVKeyAction then looks up in th
- // shortcut_table to see what the relevant handler should be
- bindings
- .slice(1)
- .forEach(binding => this._shortcut_v_table.set(binding, handler));
- } else {
- this.addOwnKeyBinding(bindings.join(' '), handler);
- }
- }
-
- override connectedCallback() {
- super.connectedCallback();
- this.restApiService.getPreferences().then(prefs => {
- if (prefs?.disable_keyboard_shortcuts) {
- this._disableKeyboardShortcuts = true;
- }
- });
- this.createVisibilityObserver();
- this.enableBindings();
- }
-
- override disconnectedCallback() {
- this.destroyVisibilityObserver();
- this.disableBindings();
- super.disconnectedCallback();
- }
-
- /**
- * Creates an intersection observer that enables bindings when the
- * element is visible and disables them when the element is hidden.
- */
- private createVisibilityObserver() {
- if (!this.hasKeyboardShortcuts()) return;
- if (this.observer) return;
- this.observer = new IntersectionObserver(entries => {
- check(entries.length === 1, 'Expected one observer entry.');
- const isVisible = entries[0].isIntersecting;
- if (isVisible) {
- this.enableBindings();
- } else {
- this.disableBindings();
- }
- });
- this.observer.observe(this.observerTarget);
- }
-
- private destroyVisibilityObserver() {
- if (this.observer) this.observer.unobserve(this.observerTarget);
- }
-
- /**
- * Enables all the shortcuts returned by keyboardShortcuts().
- * This is a private method being called when the element becomes
- * connected or visible.
- */
- private enableBindings() {
- if (!this.hasKeyboardShortcuts()) return;
- if (this.bindingsEnabled) return;
- this.bindingsEnabled = true;
-
- const shortcuts = new Map<string, string>(
- Object.entries(this.keyboardShortcuts())
- );
- shortcutManager.attachHost(this, shortcuts);
-
- for (const [key, value] of shortcuts.entries()) {
- this._addOwnKeyBindings(key as Shortcut, value);
- }
-
- // each component that uses this behaviour must be aware if go key is
- // pressed or not, since it needs to check it as a modifier
- this.addOwnKeyBinding('g:keydown', '_handleGoKeyDown');
- this.addOwnKeyBinding('g:keyup', '_handleGoKeyUp');
-
- // If any of the shortcuts utilized GO_KEY, then they are handled
- // directly by this behavior.
- if (this._shortcut_go_table.size > 0) {
- this._shortcut_go_table.forEach((_, key) => {
- this.addOwnKeyBinding(key, '_handleGoAction');
- });
- }
-
- this.addOwnKeyBinding('v:keydown', '_handleVKeyDown');
- this.addOwnKeyBinding('v:keyup', '_handleVKeyUp');
- if (this._shortcut_v_table.size > 0) {
- this._shortcut_v_table.forEach((_, key) => {
- this.addOwnKeyBinding(key, '_handleVAction');
- });
- }
- }
-
- /**
- * Disables all the shortcuts returned by keyboardShortcuts().
- * This is a private method being called when the element becomes
- * disconnected or invisible.
- */
- private disableBindings() {
- if (!this.bindingsEnabled) return;
- this.bindingsEnabled = false;
- if (shortcutManager.detachHost(this)) {
- this.removeOwnKeyBindings();
- }
- }
-
- private hasKeyboardShortcuts() {
- return Object.entries(this.keyboardShortcuts()).length > 0;
- }
-
- keyboardShortcuts() {
- return {};
- }
-
- addKeyboardShortcutDirectoryListener(listener: ShortcutListener) {
- shortcutManager.addListener(listener);
- }
-
- removeKeyboardShortcutDirectoryListener(listener: ShortcutListener) {
- shortcutManager.removeListener(listener);
- }
-
- _handleVKeyDown(e: CustomKeyboardEvent) {
- if (this.shouldSuppressKeyboardShortcut(e)) return;
- this._shortcut_v_key_last_pressed = Date.now();
- }
-
- _handleVKeyUp() {
- setTimeout(() => {
- this._shortcut_v_key_last_pressed = null;
- }, V_KEY_TIMEOUT_MS);
- }
-
- private inVKeyMode() {
- return !!(
- this._shortcut_v_key_last_pressed &&
- Date.now() - this._shortcut_v_key_last_pressed <= V_KEY_TIMEOUT_MS
- );
- }
-
- _handleVAction(e: CustomKeyboardEvent) {
- if (
- !this.inVKeyMode() ||
- !this._shortcut_v_table.has(e.detail.key) ||
- this.shouldSuppressKeyboardShortcut(e)
- ) {
- return;
- }
- e.preventDefault();
- const handler = this._shortcut_v_table.get(e.detail.key);
- if (handler) {
- // TODO(TS): should fix this
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (this as any)[handler](e);
- }
- }
-
- _handleGoKeyDown(e: CustomKeyboardEvent) {
- if (this.shouldSuppressKeyboardShortcut(e)) return;
- this._shortcut_go_key_last_pressed = Date.now();
- }
-
- _handleGoKeyUp() {
- // Set go_key_last_pressed to null `GO_KEY_TIMEOUT_MS` after keyup event
- // so that users can trigger `g + i` by pressing g and i quickly.
- setTimeout(() => {
- this._shortcut_go_key_last_pressed = null;
- }, GO_KEY_TIMEOUT_MS);
- }
-
- _inGoKeyMode() {
- return !!(
- this._shortcut_go_key_last_pressed &&
- Date.now() - this._shortcut_go_key_last_pressed <= GO_KEY_TIMEOUT_MS
- );
- }
-
- _handleGoAction(e: CustomKeyboardEvent) {
- if (
- !this._inGoKeyMode() ||
- !this._shortcut_go_table.has(e.detail.key) ||
- this.shouldSuppressKeyboardShortcut(e)
- ) {
- return;
- }
- e.preventDefault();
- const handler = this._shortcut_go_table.get(e.detail.key);
- if (handler) {
- // TODO(TS): should fix this
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- (this as any)[handler](e);
- }
+ if (bindings[0] === SPECIAL_SHORTCUT.GO_KEY) {
+ bindings
+ .slice(1)
+ .forEach(binding => this._shortcut_go_table.set(binding, handler));
+ } else if (bindings[0] === SPECIAL_SHORTCUT.V_KEY) {
+ // for each binding added with the go/v key, we set the handler to be
+ // handleVKeyAction. handleVKeyAction then looks up in th
+ // shortcut_table to see what the relevant handler should be
+ bindings
+ .slice(1)
+ .forEach(binding => this._shortcut_v_table.set(binding, handler));
+ } else {
+ this.addOwnKeyBinding(bindings.join(' '), handler);
}
}
- return Mixin;
+ override connectedCallback() {
+ super.connectedCallback();
+ this.restApiService.getPreferences().then(prefs => {
+ if (prefs?.disable_keyboard_shortcuts) {
+ this._disableKeyboardShortcuts = true;
+ }
+ });
+ this.createVisibilityObserver();
+ this.enableBindings();
+ }
+
+ override disconnectedCallback() {
+ this.destroyVisibilityObserver();
+ this.disableBindings();
+ super.disconnectedCallback();
+ }
+
+ /**
+ * Creates an intersection observer that enables bindings when the
+ * element is visible and disables them when the element is hidden.
+ */
+ private createVisibilityObserver() {
+ if (!this.hasKeyboardShortcuts()) return;
+ if (this.observer) return;
+ this.observer = new IntersectionObserver(entries => {
+ check(entries.length === 1, 'Expected one observer entry.');
+ const isVisible = entries[0].isIntersecting;
+ if (isVisible) {
+ this.enableBindings();
+ } else {
+ this.disableBindings();
+ }
+ });
+ this.observer.observe(this.observerTarget);
+ }
+
+ private destroyVisibilityObserver() {
+ if (this.observer) this.observer.unobserve(this.observerTarget);
+ }
+
+ /**
+ * Enables all the shortcuts returned by keyboardShortcuts().
+ * This is a private method being called when the element becomes
+ * connected or visible.
+ */
+ private enableBindings() {
+ if (!this.hasKeyboardShortcuts()) return;
+ if (this.bindingsEnabled) return;
+ this.bindingsEnabled = true;
+
+ const shortcuts = new Map<string, string>(
+ Object.entries(this.keyboardShortcuts())
+ );
+ shortcutManager.attachHost(this, shortcuts);
+
+ for (const [key, value] of shortcuts.entries()) {
+ this._addOwnKeyBindings(key as Shortcut, value);
+ }
+
+ // each component that uses this behaviour must be aware if go key is
+ // pressed or not, since it needs to check it as a modifier
+ this.addOwnKeyBinding('g:keydown', '_handleGoKeyDown');
+ this.addOwnKeyBinding('g:keyup', '_handleGoKeyUp');
+
+ // If any of the shortcuts utilized GO_KEY, then they are handled
+ // directly by this behavior.
+ if (this._shortcut_go_table.size > 0) {
+ this._shortcut_go_table.forEach((_, key) => {
+ this.addOwnKeyBinding(key, '_handleGoAction');
+ });
+ }
+
+ this.addOwnKeyBinding('v:keydown', '_handleVKeyDown');
+ this.addOwnKeyBinding('v:keyup', '_handleVKeyUp');
+ if (this._shortcut_v_table.size > 0) {
+ this._shortcut_v_table.forEach((_, key) => {
+ this.addOwnKeyBinding(key, '_handleVAction');
+ });
+ }
+ }
+
+ /**
+ * Disables all the shortcuts returned by keyboardShortcuts().
+ * This is a private method being called when the element becomes
+ * disconnected or invisible.
+ */
+ private disableBindings() {
+ if (!this.bindingsEnabled) return;
+ this.bindingsEnabled = false;
+ if (shortcutManager.detachHost(this)) {
+ this.removeOwnKeyBindings();
+ }
+ }
+
+ private hasKeyboardShortcuts() {
+ return Object.entries(this.keyboardShortcuts()).length > 0;
+ }
+
+ keyboardShortcuts() {
+ return {};
+ }
+
+ addKeyboardShortcutDirectoryListener(listener: ShortcutListener) {
+ shortcutManager.addListener(listener);
+ }
+
+ removeKeyboardShortcutDirectoryListener(listener: ShortcutListener) {
+ shortcutManager.removeListener(listener);
+ }
+
+ _handleVKeyDown(e: CustomKeyboardEvent) {
+ if (this.shouldSuppressKeyboardShortcut(e)) return;
+ this._shortcut_v_key_last_pressed = Date.now();
+ }
+
+ _handleVKeyUp() {
+ setTimeout(() => {
+ this._shortcut_v_key_last_pressed = null;
+ }, V_KEY_TIMEOUT_MS);
+ }
+
+ private inVKeyMode() {
+ return !!(
+ this._shortcut_v_key_last_pressed &&
+ Date.now() - this._shortcut_v_key_last_pressed <= V_KEY_TIMEOUT_MS
+ );
+ }
+
+ _handleVAction(e: CustomKeyboardEvent) {
+ if (
+ !this.inVKeyMode() ||
+ !this._shortcut_v_table.has(e.detail.key) ||
+ this.shouldSuppressKeyboardShortcut(e)
+ ) {
+ return;
+ }
+ e.preventDefault();
+ const handler = this._shortcut_v_table.get(e.detail.key);
+ if (handler) {
+ // TODO(TS): should fix this
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this as any)[handler](e);
+ }
+ }
+
+ _handleGoKeyDown(e: CustomKeyboardEvent) {
+ if (this.shouldSuppressKeyboardShortcut(e)) return;
+ this._shortcut_go_key_last_pressed = Date.now();
+ }
+
+ _handleGoKeyUp() {
+ // Set go_key_last_pressed to null `GO_KEY_TIMEOUT_MS` after keyup event
+ // so that users can trigger `g + i` by pressing g and i quickly.
+ setTimeout(() => {
+ this._shortcut_go_key_last_pressed = null;
+ }, GO_KEY_TIMEOUT_MS);
+ }
+
+ _inGoKeyMode() {
+ return !!(
+ this._shortcut_go_key_last_pressed &&
+ Date.now() - this._shortcut_go_key_last_pressed <= GO_KEY_TIMEOUT_MS
+ );
+ }
+
+ _handleGoAction(e: CustomKeyboardEvent) {
+ if (
+ !this._inGoKeyMode() ||
+ !this._shortcut_go_table.has(e.detail.key) ||
+ this.shouldSuppressKeyboardShortcut(e)
+ ) {
+ return;
+ }
+ e.preventDefault();
+ const handler = this._shortcut_go_table.get(e.detail.key);
+ if (handler) {
+ // TODO(TS): should fix this
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (this as any)[handler](e);
+ }
+ }
}
-);
+
+ return Mixin as T & Constructor<KeyboardShortcutMixinInterface>;
+};
// The following doesn't work (IronA11yKeysBehavior crashes):
-// const KeyboardShortcutMixin = dedupingMixin(superClass => {
+// const KeyboardShortcutMixin = superClass => {
// class Mixin extends mixinBehaviors([IronA11yKeysBehavior], superClass) {
// ...
// }
diff --git a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
index d5e7fe7..4536ecd 100644
--- a/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
+++ b/polygerrit-ui/app/mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin_test.js
@@ -22,6 +22,7 @@
} from './keyboard-shortcut-mixin.js';
import {html} from '@polymer/polymer/lib/utils/html-tag.js';
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
+import {mockPromise} from '../../test/test-utils.js';
const basicFixture =
fixtureFromElement('keyboard-shortcut-mixin-test-element');
@@ -271,69 +272,81 @@
});
});
- test('doesn’t block kb shortcuts for non-allowed els', done => {
+ test('doesn’t block kb shortcuts for non-allowed els', async () => {
const divEl = document.createElement('div');
element.appendChild(divEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isFalse(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(divEl, 75, null, 'k');
+ await promise;
});
- test('blocks kb shortcuts for input els', done => {
+ test('blocks kb shortcuts for input els', async () => {
const inputEl = document.createElement('input');
element.appendChild(inputEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(inputEl, 75, null, 'k');
+ await promise;
});
- test('doesn’t block kb shortcuts for checkboxes', done => {
+ test('doesn’t block kb shortcuts for checkboxes', async () => {
const inputEl = document.createElement('input');
inputEl.setAttribute('type', 'checkbox');
element.appendChild(inputEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isFalse(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(inputEl, 75, null, 'k');
+ await promise;
});
- test('blocks kb shortcuts for textarea els', done => {
+ test('blocks kb shortcuts for textarea els', async () => {
const textareaEl = document.createElement('textarea');
element.appendChild(textareaEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(textareaEl, 75, null, 'k');
+ await promise;
});
- test('blocks kb shortcuts for anything in a gr-overlay', done => {
+ test('blocks kb shortcuts for anything in a gr-overlay', async () => {
const divEl = document.createElement('div');
const element =
overlay.querySelector('keyboard-shortcut-mixin-test-element');
element.appendChild(divEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(divEl, 75, null, 'k');
+ await promise;
});
- test('blocks enter shortcut on an anchor', done => {
+ test('blocks enter shortcut on an anchor', async () => {
const anchorEl = document.createElement('a');
const element =
overlay.querySelector('keyboard-shortcut-mixin-test-element');
element.appendChild(anchorEl);
+ const promise = mockPromise();
element._handleKey = e => {
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
- done();
+ promise.resolve();
};
MockInteractions.keyDownOn(anchorEl, 13, null, 'enter');
+ await promise;
});
test('modifierPressed returns accurate values', () => {
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses.ts b/polygerrit-ui/app/node_modules_licenses/licenses.ts
index bcdab0e..ede84ff 100644
--- a/polygerrit-ui/app/node_modules_licenses/licenses.ts
+++ b/polygerrit-ui/app/node_modules_licenses/licenses.ts
@@ -45,6 +45,12 @@
/** List of licenses texts. Add the licenses here if there is no text file with license
* in package. For details - see comments for {@link LicenseInfo} and {@link PackageInfo} */
class SharedLicenses {
+ public static Lit: LicenseInfo = {
+ name: "Lit",
+ type: LicenseTypes.Bsd3,
+ sharedLicenseFile: "lit.txt",
+ };
+
public static Polymer2014: LicenseInfo = {
name: "Polymer-2014",
type: LicenseTypes.Bsd3,
@@ -97,6 +103,10 @@
const packages: PackageInfo[] = [
{
+ name: "@lit/reactive-element",
+ license: SharedLicenses.Lit,
+ },
+ {
name: "@polymer/decorators",
license: SharedLicenses.Polymer2017,
},
@@ -304,6 +314,14 @@
}
},
{
+ name: "@types/trusted-types",
+ license: {
+ name: 'DefinitelyTyped',
+ type: LicenseTypes.Mit,
+ packageLicenseFile: "LICENSE"
+ }
+ },
+ {
name: "@webcomponents/shadycss",
license: SharedLicenses.Polymer2017
},
@@ -373,20 +391,16 @@
"src/operators", "src/testing", "src/webSocket"],
},
{
+ name: "lit",
+ license: SharedLicenses.Lit,
+ },
+ {
name: "lit-element",
- license: {
- name: "lit-element",
- type: LicenseTypes.Bsd3,
- packageLicenseFile: "LICENSE"
- },
+ license: SharedLicenses.Lit,
},
{
name: "lit-html",
- license: {
- name: "lit-html",
- type: LicenseTypes.Bsd3,
- packageLicenseFile: "LICENSE"
- },
+ license: SharedLicenses.Lit,
},
{
name: "tslib",
diff --git a/polygerrit-ui/app/node_modules_licenses/licenses/lit.txt b/polygerrit-ui/app/node_modules_licenses/licenses/lit.txt
new file mode 100644
index 0000000..c8ed226
--- /dev/null
+++ b/polygerrit-ui/app/node_modules_licenses/licenses/lit.txt
@@ -0,0 +1,28 @@
+BSD 3-Clause License
+
+Copyright (c) 2017 Google LLC. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/polygerrit-ui/app/node_modules_licenses/tsconfig.json b/polygerrit-ui/app/node_modules_licenses/tsconfig.json
index c562a0c..f0a540b 100644
--- a/polygerrit-ui/app/node_modules_licenses/tsconfig.json
+++ b/polygerrit-ui/app/node_modules_licenses/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
- "target": "es6",
- "module": "commonjs",
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
diff --git a/polygerrit-ui/app/package.json b/polygerrit-ui/app/package.json
index a2e9c32..4be6241 100644
--- a/polygerrit-ui/app/package.json
+++ b/polygerrit-ui/app/package.json
@@ -38,7 +38,7 @@
"ba-linkify": "^1.0.1",
"codemirror-minified": "^5.62.2",
"immer": "^9.0.5",
- "lit-element": "^2.5.1",
+ "lit": "2.0.0-rc.3",
"page": "^1.11.6",
"polymer-bridges": "file:../../polymer-bridges/",
"polymer-resin": "^2.0.1",
diff --git a/polygerrit-ui/app/polymer.json b/polygerrit-ui/app/polymer.json
index 02ffd26..4348ba8 100644
--- a/polygerrit-ui/app/polymer.json
+++ b/polygerrit-ui/app/polymer.json
@@ -9,10 +9,13 @@
],
"lint": {
"rules": ["polymer-3"],
- "ignoreWarnings": ["deprecated-dom-call"],
+ "ignoreWarnings": [
+ "deprecated-dom-call",
+ "multiple-global-declarations"
+ ],
"filesToIgnore": [
- "**/gr-plugin-rest-api.js",
- "**/.cache/**/gr-plugin-rest-api.js"
+ "**/gr-plugin-rest-api.js",
+ "**/.cache/**/gr-plugin-rest-api.js"
]
}
}
diff --git a/polygerrit-ui/app/samples/repo-command.js b/polygerrit-ui/app/samples/repo-command.js
index acecd7d..6abb120 100644
--- a/polygerrit-ui/app/samples/repo-command.js
+++ b/polygerrit-ui/app/samples/repo-command.js
@@ -32,7 +32,7 @@
margin-bottom: var(--spacing-xxl);
}
</style>
- <h3>Plugin Bork</h3>
+ <h3 class="heading-3">Plugin Bork</h3>
<gr-button on-click="_handleCommandTap">Bork</gr-button>
`;
}
diff --git a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
index 66681ee..989bafb 100644
--- a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
@@ -35,17 +35,15 @@
provider = new GrEmailSuggestionsProvider(appContext.restApiService);
});
- test('getSuggestions', done => {
+ test('getSuggestions', async () => {
const getSuggestedAccountsStub =
stubRestApi('getSuggestedAccounts').returns(
Promise.resolve([account1, account2]));
- provider.getSuggestions('Some input').then(res => {
- assert.deepEqual(res, [account1, account2]);
- assert.isTrue(getSuggestedAccountsStub.calledOnce);
- assert.equal(getSuggestedAccountsStub.lastCall.args[0], 'Some input');
- done();
- });
+ const res = await provider.getSuggestions('Some input');
+ assert.deepEqual(res, [account1, account2]);
+ assert.isTrue(getSuggestedAccountsStub.calledOnce);
+ assert.equal(getSuggestedAccountsStub.lastCall.args[0], 'Some input');
});
test('makeSuggestionItem', () => {
diff --git a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
index 1a14abf..67f9433 100644
--- a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
@@ -36,7 +36,7 @@
provider = new GrGroupSuggestionsProvider(appContext.restApiService);
});
- test('getSuggestions', done => {
+ test('getSuggestions', async () => {
const getSuggestedAccountsStub =
stubRestApi('getSuggestedGroups')
.returns(Promise.resolve({
@@ -44,12 +44,10 @@
'Other name': {id: 3, url: 'abcd'},
}));
- provider.getSuggestions('Some input').then(res => {
- assert.deepEqual(res, [group1, group2]);
- assert.isTrue(getSuggestedAccountsStub.calledOnce);
- assert.equal(getSuggestedAccountsStub.lastCall.args[0], 'Some input');
- done();
- });
+ const res = await provider.getSuggestions('Some input');
+ assert.deepEqual(res, [group1, group2]);
+ assert.isTrue(getSuggestedAccountsStub.calledOnce);
+ assert.equal(getSuggestedAccountsStub.lastCall.args[0], 'Some input');
});
test('makeSuggestionItem', () => {
diff --git a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
index d3cad45..762d36c 100644
--- a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
@@ -54,7 +54,7 @@
let redundantSuggestion3;
let change;
- setup(done => {
+ setup(async () => {
owner = makeAccount();
existingReviewer1 = makeAccount();
existingReviewer2 = makeAccount();
@@ -78,15 +78,15 @@
},
};
- return flush(done);
+ await flush();
});
suite('allowAnyUser set to false', () => {
- setup(done => {
+ setup(async () => {
provider = GrReviewerSuggestionsProvider.create(
appContext.restApiService, change._number,
SUGGESTIONS_PROVIDERS_USERS_TYPES.REVIEWER);
- provider.init().then(done);
+ await provider.init();
});
suite('stubbed values for _getReviewerSuggestions', () => {
let getChangeSuggestedReviewersStub;
@@ -165,17 +165,15 @@
});
});
- test('getSuggestions', done => {
- provider.getSuggestions()
- .then(reviewers => {
- // Default is no filtering.
- assert.equal(reviewers.length, 6);
- assert.deepEqual(reviewers,
- [redundantSuggestion1, redundantSuggestion2,
- redundantSuggestion3, suggestion1,
- suggestion2, suggestion3]);
- })
- .then(done);
+ test('getSuggestions', async () => {
+ const reviewers = await provider.getSuggestions();
+
+ // Default is no filtering.
+ assert.equal(reviewers.length, 6);
+ assert.deepEqual(reviewers,
+ [redundantSuggestion1, redundantSuggestion2,
+ redundantSuggestion3, suggestion1,
+ suggestion2, suggestion3]);
});
test('getSuggestions short circuits when logged out', () => {
@@ -190,41 +188,37 @@
});
});
- test('getChangeSuggestedReviewers is used', done => {
+ test('getChangeSuggestedReviewers is used', async () => {
const suggestReviewerStub = stubRestApi('getChangeSuggestedReviewers')
.returns(Promise.resolve([]));
const suggestAccountStub = stubRestApi('getSuggestedAccounts')
.returns(Promise.resolve([]));
- provider.getSuggestions('').then(() => {
- assert.isTrue(suggestReviewerStub.calledOnce);
- assert.isTrue(suggestReviewerStub.calledWith(42, ''));
- assert.isFalse(suggestAccountStub.called);
- done();
- });
+ await provider.getSuggestions('');
+ assert.isTrue(suggestReviewerStub.calledOnce);
+ assert.isTrue(suggestReviewerStub.calledWith(42, ''));
+ assert.isFalse(suggestAccountStub.called);
});
});
suite('allowAnyUser set to true', () => {
- setup(done => {
+ setup(async () => {
provider = GrReviewerSuggestionsProvider.create(
appContext.restApiService, change._number,
SUGGESTIONS_PROVIDERS_USERS_TYPES.ANY);
- provider.init().then(done);
+ await provider.init();
});
- test('getSuggestedAccounts is used', done => {
+ test('getSuggestedAccounts is used', async () => {
const suggestReviewerStub = stubRestApi('getChangeSuggestedReviewers')
.returns(Promise.resolve([]));
const suggestAccountStub = stubRestApi('getSuggestedAccounts')
.returns(Promise.resolve([]));
- provider.getSuggestions('').then(() => {
- assert.isFalse(suggestReviewerStub.called);
- assert.isTrue(suggestAccountStub.calledOnce);
- assert.isTrue(suggestAccountStub.calledWith('cansee:42 '));
- done();
- });
+ await provider.getSuggestions('');
+ assert.isFalse(suggestReviewerStub.called);
+ assert.isTrue(suggestAccountStub.calledOnce);
+ assert.isTrue(suggestAccountStub.calledWith('cansee:42 '));
});
});
});
diff --git a/polygerrit-ui/app/services/checks/checks-model.ts b/polygerrit-ui/app/services/checks/checks-model.ts
index f55631b..75c24b6 100644
--- a/polygerrit-ui/app/services/checks/checks-model.ts
+++ b/polygerrit-ui/app/services/checks/checks-model.ts
@@ -30,6 +30,7 @@
import {PatchSetNumber} from '../../types/common';
import {AttemptDetail, createAttemptMap} from './checks-util';
import {assertIsDefined} from '../../utils/common-util';
+import {deepEqualStringDict, equalArray} from '../../utils/compare-util';
/**
* The checks model maintains the state of checks for two patchsets: the latest
@@ -85,6 +86,13 @@
interface ChecksProviderState {
pluginName: string;
loading: boolean;
+ /**
+ * Allows to distinguish whether loading:true is the *first* time of loading
+ * something for this provider. Or just a subsequent background update.
+ * Note that this is initially true even before loading is being set to true,
+ * so you may want to check loading && firstTimeLoad.
+ */
+ firstTimeLoad: boolean;
/** Presence of errorMessage implicitly means that the provider is in ERROR state. */
errorMessage?: string;
/** Presence of loginCallback implicitly means that the provider is in NOT_LOGGED_IN state. */
@@ -160,6 +168,15 @@
distinctUntilChanged()
);
+export const someProvidersAreLoadingFirstTime$ = checksLatest$.pipe(
+ map(state =>
+ Object.values(state).some(
+ provider => provider.loading && provider.firstTimeLoad
+ )
+ ),
+ distinctUntilChanged()
+);
+
export const someProvidersAreLoadingLatest$ = checksLatest$.pipe(
map(state =>
Object.values(state).some(providerState => providerState.loading)
@@ -184,6 +201,23 @@
distinctUntilChanged()
);
+export interface ErrorMessages {
+ /* Maps plugin name to error message. */
+ [name: string]: string;
+}
+
+export const errorMessagesLatest$ = checksLatest$.pipe(
+ map(state => {
+ const errorMessages: ErrorMessages = {};
+ for (const providerState of Object.values(state)) {
+ if (providerState.errorMessage === undefined) continue;
+ errorMessages[providerState.pluginName] = providerState.errorMessage;
+ }
+ return errorMessages;
+ }),
+ distinctUntilChanged(deepEqualStringDict)
+);
+
export const loginCallbackLatest$ = checksLatest$.pipe(
map(
state =>
@@ -194,6 +228,19 @@
distinctUntilChanged()
);
+export const topLevelActionsLatest$ = checksLatest$.pipe(
+ map(state =>
+ Object.values(state).reduce(
+ (allActions: Action[], providerState: ChecksProviderState) => [
+ ...allActions,
+ ...providerState.actions,
+ ],
+ []
+ )
+ ),
+ distinctUntilChanged<Action[]>(equalArray)
+);
+
export const topLevelActionsSelected$ = checksSelected$.pipe(
map(state =>
Object.values(state).reduce(
@@ -203,19 +250,21 @@
],
[]
)
- )
+ ),
+ distinctUntilChanged<Action[]>(equalArray)
);
export const topLevelLinksSelected$ = checksSelected$.pipe(
map(state =>
Object.values(state).reduce(
- (allActions: Link[], providerState: ChecksProviderState) => [
- ...allActions,
+ (allLinks: Link[], providerState: ChecksProviderState) => [
+ ...allLinks,
...providerState.links,
],
[]
)
- )
+ ),
+ distinctUntilChanged<Link[]>(equalArray)
);
export const allRunsLatestPatchset$ = checksLatest$.pipe(
@@ -227,7 +276,8 @@
],
[]
)
- )
+ ),
+ distinctUntilChanged<CheckRun[]>(equalArray)
);
export const allRunsSelectedPatchset$ = checksSelected$.pipe(
@@ -239,7 +289,8 @@
],
[]
)
- )
+ ),
+ distinctUntilChanged<CheckRun[]>(equalArray)
);
export const allRunsLatestPatchsetLatestAttempt$ = allRunsLatestPatchset$.pipe(
@@ -287,6 +338,7 @@
pluginState[pluginName] = {
pluginName,
loading: false,
+ firstTimeLoad: true,
runs: [],
actions: [],
links: [],
@@ -301,7 +353,7 @@
export const fakeRun0: CheckRun = {
pluginName: 'f0',
internalRunId: 'f0',
- checkName: 'FAKE Error Finder',
+ checkName: 'FAKE Error Finder Finder Finder Finder Finder Finder Finder',
labelName: 'Presubmit',
isSingleAttempt: true,
isLatestAttempt: true,
@@ -493,8 +545,8 @@
export const fakeRun4_1: CheckRun = {
pluginName: 'f4',
internalRunId: 'f4',
- checkName: 'FAKE Elimination',
- status: RunStatus.COMPLETED,
+ checkName: 'FAKE Elimination Long Long Long Long Long',
+ status: RunStatus.RUNNABLE,
attempt: 1,
isSingleAttempt: false,
isLatestAttempt: false,
@@ -504,7 +556,7 @@
export const fakeRun4_2: CheckRun = {
pluginName: 'f4',
internalRunId: 'f4',
- checkName: 'FAKE Elimination',
+ checkName: 'FAKE Elimination Long Long Long Long Long',
status: RunStatus.COMPLETED,
attempt: 2,
isSingleAttempt: false,
@@ -522,7 +574,7 @@
export const fakeRun4_3: CheckRun = {
pluginName: 'f4',
internalRunId: 'f4',
- checkName: 'FAKE Elimination',
+ checkName: 'FAKE Elimination Long Long Long Long Long',
status: RunStatus.COMPLETED,
attempt: 3,
isSingleAttempt: false,
@@ -540,13 +592,13 @@
export const fakeRun4_4: CheckRun = {
pluginName: 'f4',
internalRunId: 'f4',
- checkName: 'FAKE Elimination',
+ checkName: 'FAKE Elimination Long Long Long Long Long',
checkDescription: 'Shows you the possible eliminations.',
checkLink: 'https://www.google.com',
- status: RunStatus.RUNNING,
+ status: RunStatus.COMPLETED,
statusDescription: 'Everything was eliminated already.',
statusLink: 'https://www.google.com',
- attempt: 4,
+ attempt: 40,
scheduledTimestamp: new Date('2021-04-02T03:14:15'),
startedTimestamp: new Date('2021-04-02T04:24:25'),
finishedTimestamp: new Date('2021-04-02T04:25:44'),
@@ -568,8 +620,56 @@
],
},
],
+ actions: [
+ {
+ name: 'Re-Run',
+ tooltip: 'small',
+ primary: true,
+ callback: () => Promise.resolve({message: 'fake "re-run" triggered'}),
+ },
+ ],
};
+export function fakeRun4CreateAttempts(from: number, to: number): CheckRun[] {
+ const runs: CheckRun[] = [];
+ for (let i = from; i < to; i++) {
+ runs.push(fakeRun4CreateAttempt(i));
+ }
+ return runs;
+}
+
+export function fakeRun4CreateAttempt(attempt: number): CheckRun {
+ return {
+ pluginName: 'f4',
+ internalRunId: 'f4',
+ checkName: 'FAKE Elimination Long Long Long Long Long',
+ status: RunStatus.COMPLETED,
+ attempt,
+ isSingleAttempt: false,
+ isLatestAttempt: false,
+ attemptDetails: [],
+ results:
+ attempt % 2 === 0
+ ? [
+ {
+ internalResultId: 'f43r0',
+ category: Category.ERROR,
+ summary:
+ 'Without eliminating all the TODOs your change will break!',
+ },
+ ]
+ : [],
+ };
+}
+
+export const fakeRun4Att = [
+ fakeRun4_1,
+ fakeRun4_2,
+ fakeRun4_3,
+ ...fakeRun4CreateAttempts(5, 40),
+ fakeRun4_4,
+];
+
export const fakeActions: Action[] = [
{
name: 'Fake Action 1',
@@ -587,6 +687,7 @@
},
{
name: 'Fake Action 3',
+ summary: true,
primary: false,
tooltip: 'Tooltip for Fake Action 3',
callback: () => Promise.resolve({message: 'fake action 3 triggered'}),
@@ -674,6 +775,7 @@
pluginState[pluginName] = {
...pluginState[pluginName],
loading: false,
+ firstTimeLoad: false,
errorMessage,
loginCallback: undefined,
runs: [],
@@ -692,6 +794,7 @@
pluginState[pluginName] = {
...pluginState[pluginName],
loading: false,
+ firstTimeLoad: false,
errorMessage: undefined,
loginCallback,
runs: [],
@@ -718,6 +821,7 @@
pluginState[pluginName] = {
...pluginState[pluginName],
loading: false,
+ firstTimeLoad: false,
errorMessage: undefined,
loginCallback: undefined,
runs: runs.map(run => {
diff --git a/polygerrit-ui/app/services/checks/checks-model_test.ts b/polygerrit-ui/app/services/checks/checks-model_test.ts
index f05facb..dbd3f86 100644
--- a/polygerrit-ui/app/services/checks/checks-model_test.ts
+++ b/polygerrit-ui/app/services/checks/checks-model_test.ts
@@ -20,6 +20,7 @@
_testOnly_getState,
_testOnly_resetState,
ChecksPatchset,
+ updateStateSetLoading,
updateStateSetProvider,
updateStateSetResults,
updateStateUpdateResult,
@@ -45,34 +46,55 @@
},
];
+function current() {
+ return _testOnly_getState().pluginStateLatest[PLUGIN_NAME];
+}
+
suite('checks-model tests', () => {
test('updateStateSetProvider', () => {
_testOnly_resetState();
updateStateSetProvider(PLUGIN_NAME, ChecksPatchset.LATEST);
- const state = _testOnly_getState().pluginStateLatest[PLUGIN_NAME];
- assert.deepEqual(state, {
+ assert.deepEqual(current(), {
pluginName: PLUGIN_NAME,
loading: false,
+ firstTimeLoad: true,
runs: [],
actions: [],
links: [],
});
});
+ test('loading and first time load', () => {
+ _testOnly_resetState();
+ updateStateSetProvider(PLUGIN_NAME, ChecksPatchset.LATEST);
+ assert.isFalse(current().loading);
+ assert.isTrue(current().firstTimeLoad);
+ updateStateSetLoading(PLUGIN_NAME, ChecksPatchset.LATEST);
+ assert.isTrue(current().loading);
+ assert.isTrue(current().firstTimeLoad);
+ updateStateSetResults(PLUGIN_NAME, RUNS, [], [], ChecksPatchset.LATEST);
+ assert.isFalse(current().loading);
+ assert.isFalse(current().firstTimeLoad);
+ updateStateSetLoading(PLUGIN_NAME, ChecksPatchset.LATEST);
+ assert.isTrue(current().loading);
+ assert.isFalse(current().firstTimeLoad);
+ updateStateSetResults(PLUGIN_NAME, RUNS, [], [], ChecksPatchset.LATEST);
+ assert.isFalse(current().loading);
+ assert.isFalse(current().firstTimeLoad);
+ });
+
test('updateStateSetResults', () => {
_testOnly_resetState();
updateStateSetResults(PLUGIN_NAME, RUNS, [], [], ChecksPatchset.LATEST);
- const state = _testOnly_getState().pluginStateLatest[PLUGIN_NAME];
- assert.lengthOf(state.runs, 1);
- assert.lengthOf(state.runs[0].results!, 1);
+ assert.lengthOf(current().runs, 1);
+ assert.lengthOf(current().runs[0].results!, 1);
});
test('updateStateUpdateResult', () => {
_testOnly_resetState();
updateStateSetResults(PLUGIN_NAME, RUNS, [], [], ChecksPatchset.LATEST);
- let state = _testOnly_getState().pluginStateLatest[PLUGIN_NAME];
assert.equal(
- state.runs[0].results![0].summary,
+ current().runs[0].results![0].summary,
RUNS[0]!.results![0].summary
);
const result = RUNS[0].results![0];
@@ -83,9 +105,8 @@
updatedResult,
ChecksPatchset.LATEST
);
- state = _testOnly_getState().pluginStateLatest[PLUGIN_NAME];
- assert.lengthOf(state.runs, 1);
- assert.lengthOf(state.runs[0].results!, 1);
- assert.equal(state.runs[0].results![0].summary, 'new');
+ assert.lengthOf(current().runs, 1);
+ assert.lengthOf(current().runs[0].results!, 1);
+ assert.equal(current().runs[0].results![0].summary, 'new');
});
});
diff --git a/polygerrit-ui/app/services/checks/checks-service.ts b/polygerrit-ui/app/services/checks/checks-service.ts
index 164074b..5ebc13c 100644
--- a/polygerrit-ui/app/services/checks/checks-service.ts
+++ b/polygerrit-ui/app/services/checks/checks-service.ts
@@ -14,16 +14,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import {
catchError,
filter,
switchMap,
+ takeUntil,
takeWhile,
throttleTime,
withLatestFrom,
} from 'rxjs/operators';
import {
+ Action,
ChangeData,
CheckResult,
CheckRun,
@@ -54,13 +55,14 @@
Subject,
timer,
} from 'rxjs';
-import {ChangeInfo, PatchSetNumber} from '../../types/common';
+import {ChangeInfo, NumericChangeId, PatchSetNumber} from '../../types/common';
import {getCurrentRevision} from '../../utils/change-util';
import {getShaByPatchNum} from '../../utils/patch-set-util';
import {assertIsDefined} from '../../utils/common-util';
import {ReportingService} from '../gr-reporting/gr-reporting';
import {routerPatchNum$} from '../router/router-model';
import {Execution} from '../../constants/reporting';
+import {fireAlert, fireEvent} from '../../utils/event-util';
export class ChecksService {
private readonly providers: {[name: string]: ChecksProvider} = {};
@@ -69,11 +71,14 @@
private checkToPluginMap = new Map<string, string>();
+ private changeNum?: NumericChangeId;
+
private latestPatchNum?: PatchSetNumber;
private readonly documentVisibilityChange$ = new BehaviorSubject(undefined);
constructor(readonly reporting: ReportingService) {
+ changeNum$.subscribe(x => (this.changeNum = x));
checkToPluginMap$.subscribe(map => {
this.checkToPluginMap = map;
});
@@ -120,11 +125,50 @@
updateStateUpdateResult(pluginName, run, result, ChecksPatchset.SELECTED);
}
+ triggerAction(action?: Action, run?: CheckRun) {
+ if (!action?.callback) return;
+ if (!this.changeNum) return;
+ const patchSet = run?.patchset ?? this.latestPatchNum;
+ if (!patchSet) return;
+ const promise = action.callback(
+ this.changeNum,
+ patchSet,
+ run?.attempt,
+ run?.externalId,
+ run?.checkName,
+ action.name
+ );
+ // If plugins return undefined or not a promise, then show no toast.
+ if (!promise?.then) return;
+
+ fireAlert(document, `Triggering action '${action.name}' ...`);
+ from(promise)
+ // If the action takes longer than 5 seconds, then most likely the
+ // user is either not interested or the result not relevant anymore.
+ .pipe(takeUntil(timer(5000)))
+ .subscribe(result => {
+ if (result.errorMessage || result.message) {
+ fireAlert(document, `${result.message ?? result.errorMessage}`);
+ } else {
+ fireEvent(document, 'hide-alert');
+ }
+ if (result.shouldReload) {
+ this.reloadForCheck(run?.checkName);
+ }
+ });
+ }
+
register(
pluginName: string,
provider: ChecksProvider,
config: ChecksApiConfig
) {
+ if (this.providers[pluginName]) {
+ console.warn(
+ `Plugin '${pluginName}' was trying to register twice as a Checks UI provider. Ignored.`
+ );
+ return;
+ }
this.providers[pluginName] = provider;
this.reloadSubjects[pluginName] = new BehaviorSubject<void>(undefined);
updateStateSetProvider(pluginName, ChecksPatchset.LATEST);
diff --git a/polygerrit-ui/app/services/checks/checks-util.ts b/polygerrit-ui/app/services/checks/checks-util.ts
index 28c73d3..18cc076 100644
--- a/polygerrit-ui/app/services/checks/checks-util.ts
+++ b/polygerrit-ui/app/services/checks/checks-util.ts
@@ -157,7 +157,6 @@
export enum PRIMARY_STATUS_ACTIONS {
RERUN = 'rerun',
RUN = 'run',
- CANCEL = 'cancel',
}
export function toCanonicalAction(action: Action, status: RunStatus) {
@@ -165,20 +164,30 @@
if (status === RunStatus.COMPLETED && (name === 'run' || name === 're-run')) {
name = PRIMARY_STATUS_ACTIONS.RERUN;
}
- if (status === RunStatus.RUNNING && name === 'stop') {
- name = PRIMARY_STATUS_ACTIONS.CANCEL;
- }
return {...action, name};
}
-export function primaryActionName(status: RunStatus) {
+export function headerForStatus(status: RunStatus) {
+ switch (status) {
+ case RunStatus.COMPLETED:
+ return 'Completed';
+ case RunStatus.RUNNABLE:
+ return 'Not run';
+ case RunStatus.RUNNING:
+ return 'Running';
+ default:
+ assertNever(status, `Unsupported status: ${status}`);
+ }
+}
+
+function primaryActionName(status: RunStatus) {
switch (status) {
case RunStatus.COMPLETED:
return PRIMARY_STATUS_ACTIONS.RERUN;
case RunStatus.RUNNABLE:
return PRIMARY_STATUS_ACTIONS.RUN;
case RunStatus.RUNNING:
- return PRIMARY_STATUS_ACTIONS.CANCEL;
+ return undefined;
default:
assertNever(status, `Unsupported status: ${status}`);
}
@@ -278,21 +287,6 @@
}
}
-export function fireActionTriggered(
- target: EventTarget,
- action?: Action,
- run?: CheckRun
-) {
- if (!action) return;
- target.dispatchEvent(
- new CustomEvent('action-triggered', {
- detail: {action, run},
- composed: true,
- bubbles: true,
- })
- );
-}
-
export interface AttemptDetail {
attempt: number | undefined;
icon: string;
diff --git a/polygerrit-ui/app/services/comments/comments-model.ts b/polygerrit-ui/app/services/comments/comments-model.ts
index f7e316a..850acbc 100644
--- a/polygerrit-ui/app/services/comments/comments-model.ts
+++ b/polygerrit-ui/app/services/comments/comments-model.ts
@@ -91,12 +91,16 @@
distinctUntilChanged()
);
+function publishState(state: CommentState) {
+ privateState$.next(state);
+}
+
export function updateStateComments(comments?: {
[path: string]: CommentInfo[];
}) {
const nextState = {...privateState$.getValue()};
nextState.comments = addPath(comments) || {};
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStateRobotComments(robotComments?: {
@@ -104,13 +108,13 @@
}) {
const nextState = {...privateState$.getValue()};
nextState.robotComments = addPath(robotComments) || {};
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStateDrafts(drafts?: {[path: string]: DraftInfo[]}) {
const nextState = {...privateState$.getValue()};
nextState.drafts = addPath(drafts) || {};
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStatePortedComments(
@@ -118,19 +122,19 @@
) {
const nextState = {...privateState$.getValue()};
nextState.portedComments = portedComments || {};
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStatePortedDrafts(portedDrafts?: PathToCommentsInfoMap) {
const nextState = {...privateState$.getValue()};
nextState.portedDrafts = portedDrafts || {};
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStateAddDiscardedDraft(draft: DraftInfo) {
const nextState = {...privateState$.getValue()};
nextState.discardedDrafts = [...nextState.discardedDrafts, draft];
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStateUndoDiscardedDraft(draftID?: string) {
@@ -142,7 +146,7 @@
}
drafts.splice(index, 1);
nextState.discardedDrafts = drafts;
- privateState$.next(nextState);
+ publishState(nextState);
}
export function updateStateAddDraft(draft: DraftInfo) {
@@ -162,7 +166,25 @@
} else {
drafts[draft.path].push(draft);
}
- privateState$.next(nextState);
+ publishState(nextState);
+}
+
+export function updateStateUpdateDraft(draft: DraftInfo) {
+ const nextState = {...privateState$.getValue()};
+ if (!draft.path) throw new Error('draft path undefined');
+ nextState.drafts = {...nextState.drafts};
+ const drafts = nextState.drafts;
+ if (!drafts[draft.path])
+ throw new Error('draft: trying to edit non-existent draft');
+ drafts[draft.path] = [...drafts[draft.path]];
+ const index = drafts[draft.path].findIndex(
+ d =>
+ (d.__draftID && d.__draftID === draft.__draftID) ||
+ (d.id && d.id === draft.id)
+ );
+ if (index === -1) return;
+ drafts[draft.path][index] = draft;
+ publishState(nextState);
}
export function updateStateDeleteDraft(draft: DraftInfo) {
@@ -179,6 +201,6 @@
const discardedDraft = drafts[draft.path][index];
drafts[draft.path] = [...drafts[draft.path]];
drafts[draft.path].splice(index, 1);
- privateState$.next(nextState);
+ publishState(nextState);
updateStateAddDiscardedDraft(discardedDraft);
}
diff --git a/polygerrit-ui/app/services/comments/comments-service.ts b/polygerrit-ui/app/services/comments/comments-service.ts
index 9aa297a..16ee2f7 100644
--- a/polygerrit-ui/app/services/comments/comments-service.ts
+++ b/polygerrit-ui/app/services/comments/comments-service.ts
@@ -23,6 +23,7 @@
import {
updateStateAddDraft,
updateStateDeleteDraft,
+ updateStateUpdateDraft,
updateStateComments,
updateStateRobotComments,
updateStateDrafts,
@@ -96,6 +97,14 @@
updateStateAddDraft(draft);
}
+ cancelDraft(draft: DraftInfo) {
+ updateStateUpdateDraft(draft);
+ }
+
+ editDraft(draft: DraftInfo) {
+ updateStateUpdateDraft(draft);
+ }
+
deleteDraft(draft: DraftInfo) {
updateStateDeleteDraft(draft);
}
diff --git a/polygerrit-ui/app/services/flags/flags.ts b/polygerrit-ui/app/services/flags/flags.ts
index ef5fde2..2839874 100644
--- a/polygerrit-ui/app/services/flags/flags.ts
+++ b/polygerrit-ui/app/services/flags/flags.ts
@@ -27,6 +27,5 @@
NEW_IMAGE_DIFF_UI = 'UiFeature__new_image_diff_ui',
TOKEN_HIGHLIGHTING = 'UiFeature__token_highlighting',
CHECKS_DEVELOPER = 'UiFeature__checks_developer',
- NEW_REPLY_DIALOG = 'UiFeature__new_reply_dialog',
SUBMIT_REQUIREMENTS_UI = 'UiFeature__submit_requirements_ui',
}
diff --git a/polygerrit-ui/app/services/gr-auth/gr-auth_impl.ts b/polygerrit-ui/app/services/gr-auth/gr-auth_impl.ts
index 024fa2a..c254284 100644
--- a/polygerrit-ui/app/services/gr-auth/gr-auth_impl.ts
+++ b/polygerrit-ui/app/services/gr-auth/gr-auth_impl.ts
@@ -108,7 +108,7 @@
// See https://stackoverflow.com/questions/45816743/how-to-solve-this-caution-request-is-not-finished-yet-in-chrome
try {
res.clone().text();
- } catch (error) {
+ } catch {
// Ignore error
}
@@ -306,7 +306,7 @@
// See https://stackoverflow.com/questions/45816743/how-to-solve-this-caution-request-is-not-finished-yet-in-chrome
try {
response.clone().text();
- } catch (error) {
+ } catch {
// Ignore error
}
}
diff --git a/polygerrit-ui/app/services/gr-auth/gr-auth_test.js b/polygerrit-ui/app/services/gr-auth/gr-auth_test.js
index ac93a7d..debba6d 100644
--- a/polygerrit-ui/app/services/gr-auth/gr-auth_test.js
+++ b/polygerrit-ui/app/services/gr-auth/gr-auth_test.js
@@ -34,40 +34,32 @@
fakeFetch = sinon.stub(window, 'fetch');
});
- test('auth-check returns 403', done => {
+ test('auth-check returns 403', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- done();
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
});
- test('auth-check returns 204', done => {
+ test('auth-check returns 204', async () => {
fakeFetch.returns(Promise.resolve({status: 204}));
- auth.authCheck().then(authed => {
- assert.isTrue(authed);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- done();
- });
+ const authed = await auth.authCheck();
+ assert.isTrue(authed);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
});
- test('auth-check returns 502', done => {
+ test('auth-check returns 502', async () => {
fakeFetch.returns(Promise.resolve({status: 502}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- done();
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
});
- test('auth-check failed', done => {
+ test('auth-check failed', async () => {
fakeFetch.returns(Promise.reject(new Error('random error')));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.ERROR);
- done();
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.ERROR);
});
});
@@ -80,129 +72,105 @@
fakeFetch = sinon.stub(window, 'fetch');
});
- test('cache auth-check result', done => {
+ test('cache auth-check result', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- fakeFetch.returns(Promise.resolve({status: 204}));
- auth.authCheck().then(authed2 => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ fakeFetch.returns(Promise.resolve({status: 204}));
+ const authed2 = await auth.authCheck();
+ assert.isFalse(authed2);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
});
- test('clearCache should refetch auth-check result', done => {
+ test('clearCache should refetch auth-check result', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- fakeFetch.returns(Promise.resolve({status: 204}));
- auth.clearCache();
- auth.authCheck().then(authed2 => {
- assert.isTrue(authed2);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ fakeFetch.returns(Promise.resolve({status: 204}));
+ auth.clearCache();
+ const authed2 = await auth.authCheck();
+ assert.isTrue(authed2);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
});
- test('cache expired on auth-check after certain time', done => {
+ test('cache expired on auth-check after certain time', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- clock.tick(1000 * 10000);
- fakeFetch.returns(Promise.resolve({status: 204}));
- auth.authCheck().then(authed2 => {
- assert.isTrue(authed2);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ clock.tick(1000 * 10000);
+ fakeFetch.returns(Promise.resolve({status: 204}));
+ const authed2 = await auth.authCheck();
+ assert.isTrue(authed2);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
});
- test('no cache if auth-check failed', done => {
+ test('no cache if auth-check failed', async () => {
fakeFetch.returns(Promise.reject(new Error('random error')));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.ERROR);
- assert.equal(fakeFetch.callCount, 1);
- auth.authCheck().then(() => {
- assert.equal(fakeFetch.callCount, 2);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.ERROR);
+ assert.equal(fakeFetch.callCount, 1);
+ await auth.authCheck();
+ assert.equal(fakeFetch.callCount, 2);
});
- test('fire event when switch from authed to unauthed', done => {
+ test('fire event when switch from authed to unauthed', async () => {
fakeFetch.returns(Promise.resolve({status: 204}));
- auth.authCheck().then(authed => {
- assert.isTrue(authed);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- clock.tick(1000 * 10000);
- fakeFetch.returns(Promise.resolve({status: 403}));
- const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
- auth.authCheck().then(authed2 => {
- assert.isFalse(authed2);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- assert.isTrue(emitStub.called);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isTrue(authed);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
+ clock.tick(1000 * 10000);
+ fakeFetch.returns(Promise.resolve({status: 403}));
+ const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
+ const authed2 = await auth.authCheck();
+ assert.isFalse(authed2);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ assert.isTrue(emitStub.called);
});
- test('fire event when switch from authed to error', done => {
+ test('fire event when switch from authed to error', async () => {
fakeFetch.returns(Promise.resolve({status: 204}));
- auth.authCheck().then(authed => {
- assert.isTrue(authed);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- clock.tick(1000 * 10000);
- fakeFetch.returns(Promise.reject(new Error('random error')));
- const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
- auth.authCheck().then(authed2 => {
- assert.isFalse(authed2);
- assert.isTrue(emitStub.called);
- assert.equal(auth.status, Auth.STATUS.ERROR);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isTrue(authed);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
+ clock.tick(1000 * 10000);
+ fakeFetch.returns(Promise.reject(new Error('random error')));
+ const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
+ const authed2 = await auth.authCheck();
+ assert.isFalse(authed2);
+ assert.isTrue(emitStub.called);
+ assert.equal(auth.status, Auth.STATUS.ERROR);
});
- test('no event from non-authed to other status', done => {
+ test('no event from non-authed to other status', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- clock.tick(1000 * 10000);
- fakeFetch.returns(Promise.resolve({status: 204}));
- const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
- auth.authCheck().then(authed2 => {
- assert.isTrue(authed2);
- assert.isFalse(emitStub.called);
- assert.equal(auth.status, Auth.STATUS.AUTHED);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ clock.tick(1000 * 10000);
+ fakeFetch.returns(Promise.resolve({status: 204}));
+ const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
+ const authed2 = await auth.authCheck();
+ assert.isTrue(authed2);
+ assert.isFalse(emitStub.called);
+ assert.equal(auth.status, Auth.STATUS.AUTHED);
});
- test('no event from non-authed to other status', done => {
+ test('no event from non-authed to other status', async () => {
fakeFetch.returns(Promise.resolve({status: 403}));
- auth.authCheck().then(authed => {
- assert.isFalse(authed);
- assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
- clock.tick(1000 * 10000);
- fakeFetch.returns(Promise.reject(new Error('random error')));
- const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
- auth.authCheck().then(authed2 => {
- assert.isFalse(authed2);
- assert.isFalse(emitStub.called);
- assert.equal(auth.status, Auth.STATUS.ERROR);
- done();
- });
- });
+ const authed = await auth.authCheck();
+ assert.isFalse(authed);
+ assert.equal(auth.status, Auth.STATUS.NOT_AUTHED);
+ clock.tick(1000 * 10000);
+ fakeFetch.returns(Promise.reject(new Error('random error')));
+ const emitStub = sinon.stub(appContext.eventEmitter, 'emit');
+ const authed2 = await auth.authCheck();
+ assert.isFalse(authed2);
+ assert.isFalse(emitStub.called);
+ assert.equal(auth.status, Auth.STATUS.ERROR);
});
});
@@ -211,26 +179,22 @@
sinon.stub(window, 'fetch').returns(Promise.resolve({ok: true}));
});
- test('GET', done => {
- auth.fetch('/url', {bar: 'bar'}).then(() => {
- const [url, options] = fetch.lastCall.args;
- assert.equal(url, '/url');
- assert.equal(options.credentials, 'same-origin');
- done();
- });
+ test('GET', async () => {
+ await auth.fetch('/url', {bar: 'bar'});
+ const [url, options] = fetch.lastCall.args;
+ assert.equal(url, '/url');
+ assert.equal(options.credentials, 'same-origin');
});
- test('POST', done => {
+ test('POST', async () => {
sinon.stub(auth, '_getCookie')
.withArgs('XSRF_TOKEN')
.returns('foobar');
- auth.fetch('/url', {method: 'POST'}).then(() => {
- const [url, options] = fetch.lastCall.args;
- assert.equal(url, '/url');
- assert.equal(options.credentials, 'same-origin');
- assert.equal(options.headers.get('X-Gerrit-Auth'), 'foobar');
- done();
- });
+ await auth.fetch('/url', {method: 'POST'});
+ const [url, options] = fetch.lastCall.args;
+ assert.equal(url, '/url');
+ assert.equal(options.credentials, 'same-origin');
+ assert.equal(options.headers.get('X-Gerrit-Auth'), 'foobar');
});
});
@@ -254,45 +218,36 @@
auth.setup(getToken);
});
- test('base url support', done => {
+ test('base url support', async () => {
const baseUrl = 'http://foo';
stubBaseUrl(baseUrl);
- auth.fetch(baseUrl + '/url', {bar: 'bar'}).then(() => {
- const [url] = fetch.lastCall.args;
- assert.equal(url, 'http://foo/a/url?access_token=zbaz');
- done();
- });
+ await auth.fetch(baseUrl + '/url', {bar: 'bar'});
+ const [url] = fetch.lastCall.args;
+ assert.equal(url, 'http://foo/a/url?access_token=zbaz');
});
- test('fetch not signed in', done => {
+ test('fetch not signed in', async () => {
getToken.returns(Promise.resolve());
- auth.fetch('/url', {bar: 'bar'}).then(() => {
- const [url, options] = fetch.lastCall.args;
- assert.equal(url, '/url');
- assert.equal(options.bar, 'bar');
- assert.equal(Object.keys(options.headers).length, 0);
- done();
- });
+ await auth.fetch('/url', {bar: 'bar'});
+ const [url, options] = fetch.lastCall.args;
+ assert.equal(url, '/url');
+ assert.equal(options.bar, 'bar');
+ assert.equal(Object.keys(options.headers).length, 0);
});
- test('fetch signed in', done => {
- auth.fetch('/url', {bar: 'bar'}).then(() => {
- const [url, options] = fetch.lastCall.args;
- assert.equal(url, '/a/url?access_token=zbaz');
- assert.equal(options.bar, 'bar');
- done();
- });
+ test('fetch signed in', async () => {
+ await auth.fetch('/url', {bar: 'bar'});
+ const [url, options] = fetch.lastCall.args;
+ assert.equal(url, '/a/url?access_token=zbaz');
+ assert.equal(options.bar, 'bar');
});
- test('getToken calls are cached', done => {
- Promise.all([
- auth.fetch('/url-one'), auth.fetch('/url-two')]).then(() => {
- assert.equal(getToken.callCount, 1);
- done();
- });
+ test('getToken calls are cached', async () => {
+ await Promise.all([auth.fetch('/url-one'), auth.fetch('/url-two')]);
+ assert.equal(getToken.callCount, 1);
});
- test('getToken refreshes token', done => {
+ test('getToken refreshes token', async () => {
sinon.stub(auth, '_isTokenValid');
auth._isTokenValid
.onFirstCall().returns(true)
@@ -300,27 +255,21 @@
.returns(false)
.onThirdCall()
.returns(true);
- auth.fetch('/url-one')
- .then(() => {
- getToken.returns(Promise.resolve(makeToken('bzzbb')));
- return auth.fetch('/url-two');
- })
- .then(() => {
- const [[firstUrl], [secondUrl]] = fetch.args;
- assert.equal(firstUrl, '/a/url-one?access_token=zbaz');
- assert.equal(secondUrl, '/a/url-two?access_token=bzzbb');
- done();
- });
+ await auth.fetch('/url-one');
+ getToken.returns(Promise.resolve(makeToken('bzzbb')));
+ await auth.fetch('/url-two');
+
+ const [[firstUrl], [secondUrl]] = fetch.args;
+ assert.equal(firstUrl, '/a/url-one?access_token=zbaz');
+ assert.equal(secondUrl, '/a/url-two?access_token=bzzbb');
});
- test('signed in token error falls back to anonymous', done => {
+ test('signed in token error falls back to anonymous', async () => {
getToken.returns(Promise.resolve('rubbish'));
- auth.fetch('/url', {bar: 'bar'}).then(() => {
- const [url, options] = fetch.lastCall.args;
- assert.equal(url, '/url');
- assert.equal(options.bar, 'bar');
- done();
- });
+ await auth.fetch('/url', {bar: 'bar'});
+ const [url, options] = fetch.lastCall.args;
+ assert.equal(url, '/url');
+ assert.equal(options.bar, 'bar');
});
test('_isTokenValid', () => {
@@ -337,37 +286,33 @@
}));
});
- test('HTTP PUT with content type', done => {
+ test('HTTP PUT with content type', async () => {
const originalOptions = {
method: 'PUT',
headers: new Headers({'Content-Type': 'mail/pigeon'}),
};
- auth.fetch('/url', originalOptions).then(() => {
- assert.isTrue(getToken.called);
- const [url, options] = fetch.lastCall.args;
- assert.include(url, '$ct=mail%2Fpigeon');
- assert.include(url, '$m=PUT');
- assert.include(url, 'access_token=zbaz');
- assert.equal(options.method, 'POST');
- assert.equal(options.headers.get('Content-Type'), 'text/plain');
- done();
- });
+ await auth.fetch('/url', originalOptions);
+ assert.isTrue(getToken.called);
+ const [url, options] = fetch.lastCall.args;
+ assert.include(url, '$ct=mail%2Fpigeon');
+ assert.include(url, '$m=PUT');
+ assert.include(url, 'access_token=zbaz');
+ assert.equal(options.method, 'POST');
+ assert.equal(options.headers.get('Content-Type'), 'text/plain');
});
- test('HTTP PUT without content type', done => {
+ test('HTTP PUT without content type', async () => {
const originalOptions = {
method: 'PUT',
};
- auth.fetch('/url', originalOptions).then(() => {
- assert.isTrue(getToken.called);
- const [url, options] = fetch.lastCall.args;
- assert.include(url, '$ct=text%2Fplain');
- assert.include(url, '$m=PUT');
- assert.include(url, 'access_token=zbaz');
- assert.equal(options.method, 'POST');
- assert.equal(options.headers.get('Content-Type'), 'text/plain');
- done();
- });
+ await auth.fetch('/url', originalOptions);
+ assert.isTrue(getToken.called);
+ const [url, options] = fetch.lastCall.args;
+ assert.include(url, '$ct=text%2Fplain');
+ assert.include(url, '$m=PUT');
+ assert.include(url, 'access_token=zbaz');
+ assert.equal(options.method, 'POST');
+ assert.equal(options.headers.get('Content-Type'), 'text/plain');
});
});
});
diff --git a/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js b/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
index 6ce5eea..54a0f72e 100644
--- a/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
+++ b/polygerrit-ui/app/services/gr-event-interface/gr-event-interface_test.js
@@ -16,6 +16,7 @@
*/
import '../../test/common-test-setup-karma.js';
+import {mockPromise} from '../../test/test-utils.js';
import {EventEmitter} from './gr-event-interface_impl.js';
suite('gr-event-interface tests', () => {
@@ -29,37 +30,42 @@
gerrit.removeAllListeners();
});
- test('communicate between plugin and Gerrit', done => {
+ test('communicate between plugin and Gerrit', async () => {
const eventName = 'test-plugin-event';
let p;
+ const promise = mockPromise();
gerrit.on(eventName, e => {
assert.equal(e.value, 'test');
assert.equal(e.plugin, p);
- done();
+ promise.resolve();
});
gerrit.install(plugin => {
p = plugin;
gerrit.emit(eventName, {value: 'test', plugin});
}, '0.1',
'http://test.com/plugins/testplugin/static/test.js');
+ await promise;
});
- test('listen on events from core', done => {
+ test('listen on events from core', async () => {
const eventName = 'test-plugin-event';
+ const promise = mockPromise();
gerrit.on(eventName, e => {
assert.equal(e.value, 'test');
- done();
+ promise.resolve();
});
gerrit.emit(eventName, {value: 'test'});
+ await promise;
});
- test('communicate across plugins', done => {
+ test('communicate across plugins', async () => {
const eventName = 'test-plugin-event';
+ const promise = mockPromise();
gerrit.install(plugin => {
gerrit.on(eventName, e => {
assert.equal(e.plugin.getPluginName(), 'testB');
- done();
+ promise.resolve();
});
}, '0.1',
'http://test.com/plugins/testA/static/testA.js');
@@ -68,6 +74,7 @@
gerrit.emit(eventName, {plugin});
}, '0.1',
'http://test.com/plugins/testB/static/testB.js');
+ await promise;
});
});
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
index 1445a59..06f1a0c 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
@@ -57,6 +57,7 @@
reportExtension(name: string): void;
pluginLoaded(name: string): void;
pluginsLoaded(pluginsList?: string[]): void;
+ pluginsFailed(pluginsList?: string[]): void;
error(err: Error, reporter?: string, details?: EventDetails): void;
/**
* Reset named timer.
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 0df7d12..65a5784 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -636,6 +636,18 @@
);
}
+ pluginsFailed(pluginsList?: string[]) {
+ if (!pluginsList || pluginsList.length === 0) return;
+ this.reporter(
+ LIFECYCLE.TYPE,
+ LIFECYCLE.CATEGORY.PLUGINS_INSTALLED,
+ LifeCycle.PLUGINS_FAILED,
+ undefined,
+ {pluginsList: pluginsList || []},
+ true
+ );
+ }
+
/**
* Reset named Timing.
*/
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 13461bf..337cf2f 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -56,6 +56,7 @@
},
pluginLoaded: () => {},
pluginsLoaded: () => {},
+ pluginsFailed: () => {},
recordDraftInteraction: () => {},
reporter: () => {},
reportErrorDialog: (message: string) => {
diff --git a/polygerrit-ui/app/styles/dashboard-header-styles.ts b/polygerrit-ui/app/styles/dashboard-header-styles.ts
index 2bbca63..643a76a 100644
--- a/polygerrit-ui/app/styles/dashboard-header-styles.ts
+++ b/polygerrit-ui/app/styles/dashboard-header-styles.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
diff --git a/polygerrit-ui/app/styles/gr-a11y-styles.ts b/polygerrit-ui/app/styles/gr-a11y-styles.ts
new file mode 100644
index 0000000..a1fa62b
--- /dev/null
+++ b/polygerrit-ui/app/styles/gr-a11y-styles.ts
@@ -0,0 +1,42 @@
+/**
+ * @license
+ * 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.
+ */
+import {css} from 'lit';
+
+export const a11yStyles = css`
+ .assistive-tech-only {
+ user-select: none;
+ clip: rect(1px, 1px, 1px, 1px);
+ height: 1px;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ white-space: nowrap;
+ width: 1px;
+ z-index: -1000;
+ }
+`;
+
+const $_documentContainer = document.createElement('template');
+$_documentContainer.innerHTML = `<dom-module id="gr-a11y-styles">
+ <template>
+ <style>
+ ${a11yStyles.cssText}
+ </style>
+ </template>
+</dom-module>`;
+document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/styles/gr-font-styles.ts b/polygerrit-ui/app/styles/gr-font-styles.ts
new file mode 100644
index 0000000..422a7c5
--- /dev/null
+++ b/polygerrit-ui/app/styles/gr-font-styles.ts
@@ -0,0 +1,61 @@
+/**
+ * @license
+ * Copyright (C) 2017 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 {css} from 'lit';
+
+export const fontStyles = css`
+ .font-normal {
+ font-size: var(--font-size-normal);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-normal);
+ }
+ .font-small {
+ font-size: var(--font-size-small);
+ font-weight: var(--font-weight-normal);
+ line-height: var(--line-height-small);
+ }
+ .heading-1 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h1);
+ font-weight: var(--font-weight-h1);
+ line-height: var(--line-height-h1);
+ }
+ .heading-2 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h2);
+ font-weight: var(--font-weight-h2);
+ line-height: var(--line-height-h2);
+ }
+ .heading-3 {
+ font-family: var(--header-font-family);
+ font-size: var(--font-size-h3);
+ font-weight: var(--font-weight-h3);
+ line-height: var(--line-height-h3);
+ }
+ strong {
+ font-weight: var(--font-weight-bold);
+ }
+`;
+
+const $_documentContainer = document.createElement('template');
+$_documentContainer.innerHTML = `<dom-module id="gr-font-styles">
+ <template>
+ <style>
+ ${fontStyles.cssText}
+ </style>
+ </template>
+</dom-module>`;
+document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/styles/gr-form-styles.ts b/polygerrit-ui/app/styles/gr-form-styles.ts
index b9aecff9..34a6936 100644
--- a/polygerrit-ui/app/styles/gr-form-styles.ts
+++ b/polygerrit-ui/app/styles/gr-form-styles.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
export const formStyles = css`
.gr-form-styles input {
diff --git a/polygerrit-ui/app/styles/gr-menu-page-styles.ts b/polygerrit-ui/app/styles/gr-menu-page-styles.ts
index 0471a4e..5f58571 100644
--- a/polygerrit-ui/app/styles/gr-menu-page-styles.ts
+++ b/polygerrit-ui/app/styles/gr-menu-page-styles.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
export const menuPageStyles = css`
:host {
diff --git a/polygerrit-ui/app/styles/gr-page-nav-styles.ts b/polygerrit-ui/app/styles/gr-page-nav-styles.ts
index 1b3830a..f928848 100644
--- a/polygerrit-ui/app/styles/gr-page-nav-styles.ts
+++ b/polygerrit-ui/app/styles/gr-page-nav-styles.ts
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
diff --git a/polygerrit-ui/app/styles/gr-spinner-styles.ts b/polygerrit-ui/app/styles/gr-spinner-styles.ts
index 6fb1ae6..6015be4 100644
--- a/polygerrit-ui/app/styles/gr-spinner-styles.ts
+++ b/polygerrit-ui/app/styles/gr-spinner-styles.ts
@@ -14,14 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css} from 'lit-element';
-
-// Mark the file as a module. Otherwise typescript assumes this is a script
-// and $_documentContainer is a global variable.
-// See: https://www.typescriptlang.org/docs/handbook/modules.html
-export {};
-
-const $_documentContainer = document.createElement('template');
+import {css} from 'lit';
export const spinnerStyles = css`
.loadingSpin {
@@ -43,6 +36,7 @@
}
`;
+const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="gr-spinner-styles">
<template>
<style>
diff --git a/polygerrit-ui/app/styles/gr-subpage-styles.ts b/polygerrit-ui/app/styles/gr-subpage-styles.ts
index fa3e55f..e426a7d 100644
--- a/polygerrit-ui/app/styles/gr-subpage-styles.ts
+++ b/polygerrit-ui/app/styles/gr-subpage-styles.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
export const subpageStyles = css`
.main {
diff --git a/polygerrit-ui/app/styles/gr-table-styles.ts b/polygerrit-ui/app/styles/gr-table-styles.ts
index 72e36e1..6871499 100644
--- a/polygerrit-ui/app/styles/gr-table-styles.ts
+++ b/polygerrit-ui/app/styles/gr-table-styles.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {css} from 'lit-element';
+import {css} from 'lit';
export const tableStyles = css`
.genericList {
diff --git a/polygerrit-ui/app/styles/gr-voting-styles.ts b/polygerrit-ui/app/styles/gr-voting-styles.ts
index cb8b0be8..a623d99 100644
--- a/polygerrit-ui/app/styles/gr-voting-styles.ts
+++ b/polygerrit-ui/app/styles/gr-voting-styles.ts
@@ -18,33 +18,26 @@
// Mark the file as a module. Otherwise typescript assumes this is a script
// and $_documentContainer is a global variable.
// See: https://www.typescriptlang.org/docs/handbook/modules.html
-export {};
+import {css} from 'lit';
+
+export const votingStyles = css`
+ .voteChip {
+ border: 1px solid var(--border-color);
+ /* max rounded */
+ border-radius: 1em;
+ box-shadow: none;
+ box-sizing: border-box;
+ min-width: 3em;
+ color: var(--vote-text-color);
+ }
+`;
const $_documentContainer = document.createElement('template');
-
$_documentContainer.innerHTML = `<dom-module id="gr-voting-styles">
<template>
<style>
- :host {
- --vote-chip-styles: {
- border-style: solid;
- border-color: var(--border-color);
- border-top-left-radius: 1em;
- border-top-right-radius: 1em;
- border-bottom-right-radius: 1em;
- border-bottom-left-radius: 1em;
- border-top-width: 1px;
- border-right-width: 1px;
- border-bottom-width: 1px;
- border-left-width: 1px;
- box-shadow: none;
- box-sizing: border-box;
- min-width: 3em;
- color: var(--vote-text-color);
- }
- }
+ ${votingStyles.cssText}
</style>
</template>
</dom-module>`;
-
document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/styles/shared-styles.ts b/polygerrit-ui/app/styles/shared-styles.ts
index a8274cc..98f6eb2 100644
--- a/polygerrit-ui/app/styles/shared-styles.ts
+++ b/polygerrit-ui/app/styles/shared-styles.ts
@@ -14,15 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-import {css} from 'lit-element';
-
-// Mark the file as a module. Otherwise typescript assumes this is a script
-// and $_documentContainer is a global variable.
-// See: https://www.typescriptlang.org/docs/handbook/modules.html
-export {};
-
-const $_documentContainer = document.createElement('template');
+import {css} from 'lit';
export const sharedStyles = css`
/* CSS reset */
@@ -176,36 +168,6 @@
border-spacing: 0;
}
- /* Fonts */
-
- .font-normal {
- font-size: var(--font-size-normal);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-normal);
- }
- .font-small {
- font-size: var(--font-size-small);
- font-weight: var(--font-weight-normal);
- line-height: var(--line-height-small);
- }
- .heading-1 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h1);
- font-weight: var(--font-weight-h1);
- line-height: var(--line-height-h1);
- }
- .heading-2 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h2);
- font-weight: var(--font-weight-h2);
- line-height: var(--line-height-h2);
- }
- .heading-3 {
- font-family: var(--header-font-family);
- font-size: var(--font-size-h3);
- font-weight: var(--font-weight-h3);
- line-height: var(--line-height-h3);
- }
iron-icon {
color: var(--deemphasized-text-color);
vertical-align: top;
@@ -261,22 +223,6 @@
/** This is needed for firefox */
--iron-autogrow-textarea_-_white-space: pre-wrap;
}
- strong {
- font-weight: var(--font-weight-bold);
- }
-
- .assistive-tech-only {
- user-select: none;
- clip: rect(1px, 1px, 1px, 1px);
- height: 1px;
- margin: 0;
- overflow: hidden;
- padding: 0;
- position: absolute;
- white-space: nowrap;
- width: 1px;
- z-index: -1000;
- }
/**
* TODO: Remove these rules and change (plugin) users to rely on
@@ -303,6 +249,7 @@
/** END: loading spiner */
`;
+const $_documentContainer = document.createElement('template');
$_documentContainer.innerHTML = `<dom-module id="shared-styles">
<template>
<style>
@@ -310,5 +257,4 @@
</style>
</template>
</dom-module>`;
-
document.head.appendChild($_documentContainer.content);
diff --git a/polygerrit-ui/app/test/@types/sinon-esm.d.ts b/polygerrit-ui/app/test/@types/sinon-esm.d.ts
deleted file mode 100644
index 9074a7a..0000000
--- a/polygerrit-ui/app/test/@types/sinon-esm.d.ts
+++ /dev/null
@@ -1,27 +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.
- */
-
-declare module 'sinon/pkg/sinon-esm' {
- // sinon-esm doesn't have it's own d.ts, reexport all types from sinon
- // This is a trick - @types/sinon adds interfaces and sinon instance
- // to a global variables/namespace. We reexport it here, so we
- // can use in our code when importing sinon-esm
- // eslint-disable-next-line import/no-default-export
- export default sinon;
- const sinon: Sinon.SinonStatic;
- export {SinonSpy, SinonFakeTimers, SinonStubbedMember};
-}
diff --git a/polygerrit-ui/app/test/common-test-setup.ts b/polygerrit-ui/app/test/common-test-setup.ts
index 5096e09..550d3df 100644
--- a/polygerrit-ui/app/test/common-test-setup.ts
+++ b/polygerrit-ui/app/test/common-test-setup.ts
@@ -33,7 +33,6 @@
TestKeyboardShortcutBinder,
} from './test-utils';
import {_testOnly_getShortcutManagerInstance} from '../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
-import sinon from 'sinon/pkg/sinon-esm';
import {safeTypesBridge} from '../utils/safe-types-util';
import {_testOnly_initGerritPluginApi} from '../elements/shared/gr-js-api-interface/gr-gerrit';
import {initGlobalVariables} from '../elements/gr-app-global-var-init';
diff --git a/polygerrit-ui/app/test/test-data-generators.ts b/polygerrit-ui/app/test/test-data-generators.ts
index c82c15b..db84043 100644
--- a/polygerrit-ui/app/test/test-data-generators.ts
+++ b/polygerrit-ui/app/test/test-data-generators.ts
@@ -106,6 +106,8 @@
SubmitRequirementResultInfo,
SubmitRequirementStatus,
} from '../api/rest-api';
+import {RunResult} from '../services/checks/checks-model';
+import {Category, RunStatus} from '../api/checks';
export function dateToTimestamp(date: Date): Timestamp {
const nanosecondSuffix = '.000000000';
@@ -688,3 +690,19 @@
submittability_expression_result: createSubmitRequirementExpressionInfo(),
};
}
+
+export function createRunResult(): RunResult {
+ return {
+ attemptDetails: [],
+ category: Category.INFO,
+ checkName: 'test-name',
+ internalResultId: 'test-internal-result-id',
+ internalRunId: 'test-internal-run-id',
+ isLatestAttempt: true,
+ isSingleAttempt: true,
+ pluginName: 'test-plugin-name',
+ status: RunStatus.COMPLETED,
+ summary: 'This is the test summary.',
+ message: 'This is the test message.',
+ };
+}
diff --git a/polygerrit-ui/app/test/test-utils.ts b/polygerrit-ui/app/test/test-utils.ts
index 03a9525..a60c1d1 100644
--- a/polygerrit-ui/app/test/test-utils.ts
+++ b/polygerrit-ui/app/test/test-utils.ts
@@ -23,11 +23,12 @@
} from '../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
import {appContext} from '../services/app-context';
import {RestApiService} from '../services/gr-rest-api/gr-rest-api';
-import {SinonSpy} from 'sinon/pkg/sinon-esm';
+import {SinonSpy} from 'sinon';
import {StorageService} from '../services/storage/gr-storage';
import {AuthService} from '../services/gr-auth/gr-auth';
import {ReportingService} from '../services/gr-reporting/gr-reporting';
import {CommentsService} from '../services/comments/comments-service';
+export {query, queryAll, queryAndAssert} from '../utils/common-util';
export interface MockPromise extends Promise<unknown> {
resolve: (value?: unknown) => void;
@@ -47,33 +48,6 @@
return getComputedStyle(el).display === 'none';
}
-export function queryAll<E extends Element = Element>(
- el: Element | undefined,
- selector: string
-): NodeListOf<E> {
- if (!el) assert.fail('element not defined');
- const root = el.shadowRoot ?? el;
- return root.querySelectorAll<E>(selector);
-}
-
-export function query<E extends Element = Element>(
- el: Element | undefined,
- selector: string
-): E | undefined {
- if (!el) return undefined;
- const root = el.shadowRoot ?? el;
- return root.querySelector<E>(selector) ?? undefined;
-}
-
-export function queryAndAssert<E extends Element = Element>(
- el: Element | undefined,
- selector: string
-): E {
- const found = query<E>(el, selector);
- if (!found) assert.fail(`selector '${selector}' did not match anything'`);
- return found;
-}
-
export function isVisible(el: Element) {
assert.ok(el);
return getComputedStyle(el).getPropertyValue('display') !== 'none';
@@ -218,6 +192,27 @@
el.parentNode?.removeChild(el);
}
+export function waitUntil(
+ predicate: () => boolean,
+ maxMillis = 100
+): Promise<void> {
+ const start = Date.now();
+ let sleep = 1;
+ return new Promise((resolve, reject) => {
+ const waiter = () => {
+ if (predicate()) {
+ return resolve();
+ }
+ if (Date.now() - start >= maxMillis) {
+ return reject(new Error('Took to long to waitUntil'));
+ }
+ setTimeout(waiter, sleep);
+ sleep *= 2;
+ };
+ waiter();
+ });
+}
+
/**
* Promisify an event callback to simplify async...await tests.
*
diff --git a/polygerrit-ui/app/tsconfig.json b/polygerrit-ui/app/tsconfig.json
index a533a0f..7b01226 100644
--- a/polygerrit-ui/app/tsconfig.json
+++ b/polygerrit-ui/app/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
/* Basic Options */
- "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowJs": true, /* Allow javascript files to be compiled. */
"checkJs": false, /* Report errors in .js files. */
@@ -25,6 +25,7 @@
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
+ "noImplicitOverride": true,
"noFallthroughCasesInSwitch": true,/* Report errors for fallthrough cases in switch statement. */
"skipLibCheck": true, /* Do not check node_modules */
@@ -39,7 +40,13 @@
"incremental": true,
"experimentalDecorators": true,
- "allowUmdGlobalAccess": true
+ "allowUmdGlobalAccess": true,
+
+ /* typeRoots for IDE (see tsconfig_bazel.json for Bazel) */
+ "typeRoots": [
+ "node_modules/@types",
+ "../node_modules/@types"
+ ]
},
// With the * pattern (without an extension), only supported files
// are included. The supported files are .ts, .tsx, .d.ts.
diff --git a/polygerrit-ui/app/tsconfig_bazel_test.json b/polygerrit-ui/app/tsconfig_bazel_test.json
index 9c2ff93..7137e23 100644
--- a/polygerrit-ui/app/tsconfig_bazel_test.json
+++ b/polygerrit-ui/app/tsconfig_bazel_test.json
@@ -2,7 +2,6 @@
"extends": "./tsconfig_bazel.json",
"compilerOptions": {
"typeRoots": [
- "./test/@types",
"../../external/ui_dev_npm/node_modules/@polymer/iron-test-helpers",
"../../external/ui_npm/node_modules/@types",
"../../external/ui_dev_npm/node_modules/@types"
diff --git a/polygerrit-ui/app/types/common.ts b/polygerrit-ui/app/types/common.ts
index 696ab63..1617aa3 100644
--- a/polygerrit-ui/app/types/common.ts
+++ b/polygerrit-ui/app/types/common.ts
@@ -37,6 +37,7 @@
import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
import {
AccountId,
+ AccountDetailInfo,
AccountInfo,
AccountsConfigInfo,
ActionInfo,
@@ -125,6 +126,7 @@
export {
AccountId,
+ AccountDetailInfo,
AccountInfo,
AccountsConfigInfo,
ActionInfo,
@@ -285,14 +287,6 @@
}
/**
- * The AccountDetailInfo entity contains detailed information about an account.
- * https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#account-detail-info
- */
-export interface AccountDetailInfo extends AccountInfo {
- registered_on: Timestamp;
-}
-
-/**
* The AccountExternalIdInfo entity contains information for an external id of
* an account.
* https://gerrit-review.googlesource.com/Documentation/rest-api-accounts.html#account-external-id-info
@@ -1149,6 +1143,7 @@
default_base_for_merges: DefaultBase;
publish_comments_on_push?: boolean;
disable_keyboard_shortcuts?: boolean;
+ disable_token_highlighting?: boolean;
work_in_progress_by_default?: boolean;
// The email_format doesn't mentioned in doc, but exists in Java class GeneralPreferencesInfo
email_format?: EmailFormat;
diff --git a/polygerrit-ui/app/types/globals.ts b/polygerrit-ui/app/types/globals.ts
index a06c2c4..b5bd2aa 100644
--- a/polygerrit-ui/app/types/globals.ts
+++ b/polygerrit-ui/app/types/globals.ts
@@ -75,4 +75,8 @@
lineNumber?: number; // non-standard property
columnNumber?: number; // non-standard property
}
+
+ interface ShadowRoot {
+ getSelection?: () => Selection | null;
+ }
}
diff --git a/polygerrit-ui/app/utils/access-util.ts b/polygerrit-ui/app/utils/access-util.ts
index 44830e2..165eacf 100644
--- a/polygerrit-ui/app/utils/access-util.ts
+++ b/polygerrit-ui/app/utils/access-util.ts
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import {LabelName} from '../types/common';
+import {GitRef, LabelName} from '../types/common';
export enum AccessPermissionId {
ABANDON = 'abandon',
@@ -156,7 +156,7 @@
}
export interface PermissionArrayItem<T> {
- id: string;
+ id: GitRef;
value: T;
}
@@ -175,7 +175,7 @@
return Object.keys(obj)
.map(key => {
return {
- id: key,
+ id: key as GitRef,
value: obj[key],
};
})
diff --git a/polygerrit-ui/app/utils/admin-nav-util_test.js b/polygerrit-ui/app/utils/admin-nav-util_test.js
index ae2e7a9..2a13904 100644
--- a/polygerrit-ui/app/utils/admin-nav-util_test.js
+++ b/polygerrit-ui/app/utils/admin-nav-util_test.js
@@ -27,71 +27,69 @@
menuLinkStub = sinon.stub().returns([]);
});
- const testAdminLinks = (account, options, expected, done) => {
- getAdminLinks(account,
+ const testAdminLinks = async (account, options, expected) => {
+ const res = await getAdminLinks(account,
capabilityStub,
menuLinkStub,
- options)
- .then(res => {
- assert.equal(expected.totalLength, res.links.length);
- assert.equal(res.links[0].name, 'Repositories');
- // Repos
- if (expected.groupListShown) {
- assert.equal(res.links[1].name, 'Groups');
- }
+ options);
- if (expected.pluginListShown) {
- assert.equal(res.links[2].name, 'Plugins');
- assert.isNotOk(res.links[2].subsection);
- }
+ assert.equal(expected.totalLength, res.links.length);
+ assert.equal(res.links[0].name, 'Repositories');
+ // Repos
+ if (expected.groupListShown) {
+ assert.equal(res.links[1].name, 'Groups');
+ }
- if (expected.projectPageShown) {
- assert.isOk(res.links[0].subsection);
- assert.equal(res.links[0].subsection.children.length, 6);
- } else {
- assert.isNotOk(res.links[0].subsection);
- }
- // Groups
- if (expected.groupPageShown) {
- assert.isOk(res.links[1].subsection);
- assert.equal(res.links[1].subsection.children.length,
- expected.groupSubpageLength);
- } else if ( expected.totalLength > 1) {
- assert.isNotOk(res.links[1].subsection);
- }
+ if (expected.pluginListShown) {
+ assert.equal(res.links[2].name, 'Plugins');
+ assert.isNotOk(res.links[2].subsection);
+ }
- if (expected.pluginGeneratedLinks) {
- for (const link of expected.pluginGeneratedLinks) {
- const linkMatch = res.links
- .find(l => (l.url === link.url && l.name === link.text));
- assert.isTrue(!!linkMatch);
+ if (expected.projectPageShown) {
+ assert.isOk(res.links[0].subsection);
+ assert.equal(res.links[0].subsection.children.length, 6);
+ } else {
+ assert.isNotOk(res.links[0].subsection);
+ }
+ // Groups
+ if (expected.groupPageShown) {
+ assert.isOk(res.links[1].subsection);
+ assert.equal(res.links[1].subsection.children.length,
+ expected.groupSubpageLength);
+ } else if ( expected.totalLength > 1) {
+ assert.isNotOk(res.links[1].subsection);
+ }
- // External links should open in new tab.
- if (link.url[0] !== '/') {
- assert.equal(linkMatch.target, '_blank');
- } else {
- assert.isNotOk(linkMatch.target);
- }
- }
- }
+ if (expected.pluginGeneratedLinks) {
+ for (const link of expected.pluginGeneratedLinks) {
+ const linkMatch = res.links
+ .find(l => (l.url === link.url && l.name === link.text));
+ assert.isTrue(!!linkMatch);
- // Current section
- if (expected.projectPageShown || expected.groupPageShown) {
- assert.isOk(res.expandedSection);
- assert.isOk(res.expandedSection.children);
- } else {
- assert.isNotOk(res.expandedSection);
- }
- if (expected.projectPageShown) {
- assert.equal(res.expandedSection.name, 'my-repo');
- assert.equal(res.expandedSection.children.length, 6);
- } else if (expected.groupPageShown) {
- assert.equal(res.expandedSection.name, 'my-group');
- assert.equal(res.expandedSection.children.length,
- expected.groupSubpageLength);
- }
- done();
- });
+ // External links should open in new tab.
+ if (link.url[0] !== '/') {
+ assert.equal(linkMatch.target, '_blank');
+ } else {
+ assert.isNotOk(linkMatch.target);
+ }
+ }
+ }
+
+ // Current section
+ if (expected.projectPageShown || expected.groupPageShown) {
+ assert.isOk(res.expandedSection);
+ assert.isOk(res.expandedSection.children);
+ } else {
+ assert.isNotOk(res.expandedSection);
+ }
+ if (expected.projectPageShown) {
+ assert.equal(res.expandedSection.name, 'my-repo');
+ assert.equal(res.expandedSection.children.length, 6);
+ } else if (expected.groupPageShown) {
+ assert.equal(res.expandedSection.name, 'my-group');
+ assert.equal(res.expandedSection.children.length,
+ expected.groupSubpageLength);
+ }
};
suite('logged out', () => {
@@ -106,25 +104,25 @@
};
});
- test('without a specific repo or group', done => {
+ test('without a specific repo or group', async () => {
let options;
expected = Object.assign(expected, {
totalLength: 1,
projectPageShown: false,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('with a repo', done => {
+ test('with a repo', async () => {
const options = {repoName: 'my-repo'};
expected = Object.assign(expected, {
totalLength: 1,
projectPageShown: true,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('with plugin generated links', done => {
+ test('with plugin generated links', async () => {
let options;
const generatedLinks = [
{text: 'internal link text', url: '/internal/link/url'},
@@ -136,7 +134,7 @@
projectPageShown: false,
pluginGeneratedLinks: generatedLinks,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
});
@@ -154,17 +152,17 @@
capabilityStub.returns(Promise.resolve({}));
});
- test('without a specific project or group', done => {
+ test('without a specific project or group', async () => {
let options;
expected = Object.assign(expected, {
projectPageShown: false,
groupListShown: true,
groupPageShown: false,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('with a repo', done => {
+ test('with a repo', async () => {
const account = {
name: 'test-user',
};
@@ -174,7 +172,7 @@
groupListShown: true,
groupPageShown: false,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
});
@@ -193,25 +191,25 @@
};
});
- test('without a specific repo or group', done => {
+ test('without a specific repo or group', async () => {
let options;
expected = Object.assign(expected, {
projectPageShown: false,
groupPageShown: false,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('with a repo', done => {
+ test('with a repo', async () => {
const options = {repoName: 'my-repo'};
expected = Object.assign(expected, {
projectPageShown: true,
groupPageShown: false,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('admin with internal group', done => {
+ test('admin with internal group', async () => {
const options = {
groupId: 'a15262',
groupName: 'my-group',
@@ -224,10 +222,10 @@
groupPageShown: true,
groupSubpageLength: 2,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('group owner with internal group', done => {
+ test('group owner with internal group', async () => {
const options = {
groupId: 'a15262',
groupName: 'my-group',
@@ -240,10 +238,10 @@
groupPageShown: true,
groupSubpageLength: 2,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('non owner or admin with internal group', done => {
+ test('non owner or admin with internal group', async () => {
const options = {
groupId: 'a15262',
groupName: 'my-group',
@@ -256,10 +254,10 @@
groupPageShown: true,
groupSubpageLength: 1,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
- test('admin with external group', done => {
+ test('admin with external group', async () => {
const options = {
groupId: 'a15262',
groupName: 'my-group',
@@ -272,7 +270,7 @@
groupPageShown: true,
groupSubpageLength: 0,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
});
@@ -287,7 +285,7 @@
expected = {};
});
- test('with plugin with capabilities', done => {
+ test('with plugin with capabilities', async () => {
let options;
const generatedLinks = [
{text: 'without capability', url: '/without'},
@@ -300,7 +298,7 @@
totalLength: 4,
pluginGeneratedLinks: generatedLinks,
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
});
@@ -315,7 +313,7 @@
expected = {};
});
- test('with plugin with capabilities', done => {
+ test('with plugin with capabilities', async () => {
let options;
const generatedLinks = [
{text: 'without capability', url: '/without'},
@@ -328,7 +326,7 @@
totalLength: 3,
pluginGeneratedLinks: [generatedLinks[0]],
});
- testAdminLinks(account, options, expected, done);
+ await testAdminLinks(account, options, expected);
});
});
});
diff --git a/polygerrit-ui/app/utils/attention-set-util.ts b/polygerrit-ui/app/utils/attention-set-util.ts
index bcb2d66..dcd2863 100644
--- a/polygerrit-ui/app/utils/attention-set-util.ts
+++ b/polygerrit-ui/app/utils/attention-set-util.ts
@@ -16,6 +16,7 @@
*/
import {AccountInfo, ChangeInfo, ServerInfo} from '../types/common';
+import {ParsedChangeInfo} from '../types/types';
import {
getAccountTemplate,
isServiceUser,
@@ -29,7 +30,7 @@
export function hasAttention(
account?: AccountInfo,
- change?: ChangeInfo
+ change?: ChangeInfo | ParsedChangeInfo
): boolean {
return (
canHaveAttention(account) &&
@@ -41,7 +42,7 @@
export function getReason(
config?: ServerInfo,
account?: AccountInfo,
- change?: ChangeInfo
+ change?: ChangeInfo | ParsedChangeInfo
) {
if (!hasAttention(account, change)) return '';
if (change?.attention_set === undefined) return '';
@@ -76,6 +77,16 @@
return `${getAccountTemplate(account, config)} replied on the change`;
}
+export function getRemovedByIconClickReason(
+ account?: AccountInfo,
+ config?: ServerInfo
+) {
+ return `Removed by ${getAccountTemplate(
+ account,
+ config
+ )} by clicking the attention icon`;
+}
+
export function getLastUpdate(account?: AccountInfo, change?: ChangeInfo) {
if (!hasAttention(account, change)) return '';
const entry = change!.attention_set![account!._account_id!];
diff --git a/polygerrit-ui/app/utils/change-metadata-util.ts b/polygerrit-ui/app/utils/change-metadata-util.ts
index a4865dc..9692ab31 100644
--- a/polygerrit-ui/app/utils/change-metadata-util.ts
+++ b/polygerrit-ui/app/utils/change-metadata-util.ts
@@ -15,9 +15,7 @@
* limitations under the License.
*/
-import {SubmitRequirementResultInfo} from '../api/rest-api';
import {ParsedChangeInfo} from '../types/types';
-import {unique} from './common-util';
export enum Metadata {
OWNER = 'Owner',
@@ -83,19 +81,3 @@
}
return true;
}
-
-export function extractAssociatedLabels(
- requirement: SubmitRequirementResultInfo
-): string[] {
- const pattern = new RegExp('label[0-9]*:([\\w-]+)', 'g');
- const labels = [];
- let match;
- while (
- (match = pattern.exec(
- requirement.submittability_expression_result.expression
- )) !== null
- ) {
- labels.push(match[1]);
- }
- return labels.filter(unique);
-}
diff --git a/polygerrit-ui/app/utils/change-metadata-util_test.ts b/polygerrit-ui/app/utils/change-metadata-util_test.ts
deleted file mode 100644
index 888114d..0000000
--- a/polygerrit-ui/app/utils/change-metadata-util_test.ts
+++ /dev/null
@@ -1,59 +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 '../test/common-test-setup-karma';
-import {
- createSubmitRequirementExpressionInfo,
- createSubmitRequirementResultInfo,
-} from '../test/test-data-generators';
-import {extractAssociatedLabels} from './change-metadata-util';
-
-suite('change-metadata-util', () => {
- suite('extractAssociatedLabels()', () => {
- function createSubmitRequirementExpressionInfoWith(expression: string) {
- return {
- ...createSubmitRequirementResultInfo(),
- submittability_expression_result: {
- ...createSubmitRequirementExpressionInfo(),
- expression,
- },
- };
- }
-
- test('1 label', () => {
- const submitRequirement = createSubmitRequirementExpressionInfoWith(
- 'label:Verified=MAX -label:Verified=MIN'
- );
- const labels = extractAssociatedLabels(submitRequirement);
- assert.deepEqual(labels, ['Verified']);
- });
- test('label with number', () => {
- const submitRequirement = createSubmitRequirementExpressionInfoWith(
- 'label2:verified=MAX'
- );
- const labels = extractAssociatedLabels(submitRequirement);
- assert.deepEqual(labels, ['verified']);
- });
- test('2 labels', () => {
- const submitRequirement = createSubmitRequirementExpressionInfoWith(
- 'label:Verified=MAX -label:Code-Review=MIN'
- );
- const labels = extractAssociatedLabels(submitRequirement);
- assert.deepEqual(labels, ['Verified', 'Code-Review']);
- });
- });
-});
diff --git a/polygerrit-ui/app/utils/change-util.ts b/polygerrit-ui/app/utils/change-util.ts
index c94493b..278e7f3 100644
--- a/polygerrit-ui/app/utils/change-util.ts
+++ b/polygerrit-ui/app/utils/change-util.ts
@@ -215,7 +215,7 @@
}
export function isUploader(
- change?: ChangeInfo,
+ change?: ChangeInfo | ParsedChangeInfo,
account?: AccountInfo
): boolean {
if (!change || !account) return false;
@@ -224,7 +224,7 @@
}
export function isInvolved(
- change?: ChangeInfo,
+ change?: ChangeInfo | ParsedChangeInfo,
account?: AccountInfo
): boolean {
const owner = isOwner(change, account);
diff --git a/polygerrit-ui/app/utils/comment-util.ts b/polygerrit-ui/app/utils/comment-util.ts
index 48d6947..5b08fab 100644
--- a/polygerrit-ui/app/utils/comment-util.ts
+++ b/polygerrit-ui/app/utils/comment-util.ts
@@ -129,6 +129,7 @@
const newThread: CommentThread = {
comments: [comment],
patchNum: comment.patch_set,
+ diffSide: Side.LEFT,
commentSide: comment.side ?? CommentSide.REVISION,
mergeParentNum: comment.parent,
path: comment.path,
diff --git a/polygerrit-ui/app/utils/common-util.ts b/polygerrit-ui/app/utils/common-util.ts
index 36c3657..0002254 100644
--- a/polygerrit-ui/app/utils/common-util.ts
+++ b/polygerrit-ui/app/utils/common-util.ts
@@ -90,8 +90,17 @@
}
}
-function query<E extends Element = Element>(
- el: Element | undefined,
+export function queryAll<E extends Element = Element>(
+ el: Element,
+ selector: string
+): NodeListOf<E> {
+ if (!el) throw new Error('element not defined');
+ const root = el.shadowRoot ?? el;
+ return root.querySelectorAll<E>(selector);
+}
+
+export function query<E extends Element = Element>(
+ el: Element | null | undefined,
selector: string
): E | undefined {
if (!el) return undefined;
@@ -100,7 +109,7 @@
}
export function queryAndAssert<E extends Element = Element>(
- el: Element | undefined,
+ el: Element | null | undefined,
selector: string
): E {
const found = query<E>(el, selector);
diff --git a/polygerrit-ui/app/utils/compare-util.ts b/polygerrit-ui/app/utils/compare-util.ts
new file mode 100644
index 0000000..dd20915
--- /dev/null
+++ b/polygerrit-ui/app/utils/compare-util.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * 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.
+ */
+export function deepEqualStringDict(
+ a: {[name: string]: string},
+ b: {[name: string]: string}
+): boolean {
+ const aKeys = Object.keys(a);
+ const bKeys = Object.keys(b);
+ if (aKeys.length !== bKeys.length) return false;
+ for (const key of aKeys) {
+ if (a[key] !== b[key]) return false;
+ }
+ return true;
+}
+
+export function equalArray(a?: unknown[], b?: unknown[]): boolean {
+ if (a === b) return true;
+ if (a === undefined) return b === undefined;
+ if (b === undefined) return a === undefined;
+ if (a.length !== b.length) return false;
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] !== b[i]) return false;
+ }
+ return true;
+}
diff --git a/polygerrit-ui/app/utils/compare-util_test.ts b/polygerrit-ui/app/utils/compare-util_test.ts
new file mode 100644
index 0000000..7cd71bf
--- /dev/null
+++ b/polygerrit-ui/app/utils/compare-util_test.ts
@@ -0,0 +1,43 @@
+/**
+ * @license
+ * 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.
+ */
+import '../test/common-test-setup-karma';
+import {deepEqualStringDict, equalArray} from './compare-util';
+
+suite('compare-utils tests', () => {
+ test('deepEqual', () => {
+ assert.isTrue(deepEqualStringDict({}, {}));
+ assert.isTrue(deepEqualStringDict({x: 'y'}, {x: 'y'}));
+ assert.isTrue(deepEqualStringDict({x: 'y', p: 'q'}, {p: 'q', x: 'y'}));
+
+ assert.isFalse(deepEqualStringDict({}, {x: 'y'}));
+ assert.isFalse(deepEqualStringDict({x: 'y'}, {x: 'z'}));
+ assert.isFalse(deepEqualStringDict({x: 'y'}, {z: 'y'}));
+ });
+
+ test('equalArray', () => {
+ assert.isTrue(equalArray(undefined, undefined));
+ assert.isTrue(equalArray([], []));
+ assert.isTrue(equalArray([1], [1]));
+ assert.isTrue(equalArray(['a', 'b'], ['a', 'b']));
+
+ assert.isFalse(equalArray(undefined, []));
+ assert.isFalse(equalArray([], undefined));
+ assert.isFalse(equalArray([], [1]));
+ assert.isFalse(equalArray([1], [2]));
+ assert.isFalse(equalArray([1, 2], [1]));
+ });
+});
diff --git a/polygerrit-ui/app/utils/dom-util.ts b/polygerrit-ui/app/utils/dom-util.ts
index e7cc956..7b1f3e3 100644
--- a/polygerrit-ui/app/utils/dom-util.ts
+++ b/polygerrit-ui/app/utils/dom-util.ts
@@ -171,7 +171,7 @@
* getEventPath(e); // eg: div.class1>p#pid.class2
* }
*/
-export function getEventPath<T extends PolymerEvent>(e?: T) {
+export function getEventPath<T extends MouseEvent>(e?: T) {
if (!e) return '';
let path = e.composedPath();
@@ -227,7 +227,7 @@
// document.activeElement is not enough, because it's not getting activeElement
// without looking inside of shadow roots. This will find best activeElement.
export function findActiveElement(
- root: DocumentOrShadowRoot | null,
+ root: Document | ShadowRoot | null,
ignoreDialogs?: boolean
): HTMLElement | null {
if (root === null) {
@@ -257,7 +257,7 @@
export function isSafari() {
return (
/^((?!chrome|android).)*safari/i.test(navigator.userAgent) ||
- (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
+ /iPad|iPhone|iPod/.test(navigator.userAgent)
);
}
diff --git a/polygerrit-ui/app/utils/label-util.ts b/polygerrit-ui/app/utils/label-util.ts
index 92bbdac..cde9a45 100644
--- a/polygerrit-ui/app/utils/label-util.ts
+++ b/polygerrit-ui/app/utils/label-util.ts
@@ -15,6 +15,11 @@
* limitations under the License.
*/
import {
+ isQuickLabelInfo,
+ SubmitRequirementResultInfo,
+ SubmitRequirementStatus,
+} from '../api/rest-api';
+import {
AccountInfo,
ApprovalInfo,
DetailedLabelInfo,
@@ -23,6 +28,7 @@
LabelNameToInfoMap,
VotingRangeInfo,
} from '../types/common';
+import {assertNever, unique} from './common-util';
// Name of the standard Code-Review label.
export const CODE_REVIEW = 'Code-Review';
@@ -64,8 +70,11 @@
return max > -min ? max : min;
}
-export function getLabelStatus(label?: DetailedLabelInfo): LabelStatus {
- const value = getRepresentativeValue(label);
+export function getLabelStatus(
+ label?: DetailedLabelInfo,
+ vote?: number
+): LabelStatus {
+ const value = vote ?? getRepresentativeValue(label);
const range = getVotingRangeOrDefault(label);
if (value < 0) {
return value === range.min ? LabelStatus.REJECTED : LabelStatus.DISLIKED;
@@ -76,6 +85,23 @@
return LabelStatus.NEUTRAL;
}
+export function classForLabelStatus(status: LabelStatus) {
+ switch (status) {
+ case LabelStatus.APPROVED:
+ return 'max';
+ case LabelStatus.RECOMMENDED:
+ return 'positive';
+ case LabelStatus.DISLIKED:
+ return 'negative';
+ case LabelStatus.REJECTED:
+ return 'min';
+ case LabelStatus.NEUTRAL:
+ return 'neutral';
+ default:
+ assertNever(status, `Unsupported status: ${status}`);
+ }
+}
+
export function valueString(value?: number) {
if (!value) return ' 0';
let s = `${value}`;
@@ -96,6 +122,19 @@
return label.all?.filter(x => x._account_id === account._account_id)[0];
}
+export function hasVotes(labelInfo: LabelInfo): boolean {
+ if (isDetailedLabelInfo(labelInfo)) {
+ return (labelInfo.all ?? []).some(
+ approval =>
+ getLabelStatus(labelInfo, approval.value) !== LabelStatus.NEUTRAL
+ );
+ }
+ if (isQuickLabelInfo(labelInfo)) {
+ return !!labelInfo.rejected || !!labelInfo.approved;
+ }
+ return false;
+}
+
export function labelCompare(labelName1: string, labelName2: string) {
if (labelName1 === CODE_REVIEW && labelName2 === CODE_REVIEW) return 0;
if (labelName1 === CODE_REVIEW) return -1;
@@ -114,3 +153,34 @@
}
return;
}
+
+export function extractAssociatedLabels(
+ requirement: SubmitRequirementResultInfo
+): string[] {
+ const pattern = new RegExp('label[0-9]*:([\\w-]+)', 'g');
+ const labels = [];
+ let match;
+ while (
+ (match = pattern.exec(
+ requirement.submittability_expression_result.expression
+ )) !== null
+ ) {
+ labels.push(match[1]);
+ }
+ return labels.filter(unique);
+}
+
+export function iconForStatus(status: SubmitRequirementStatus) {
+ switch (status) {
+ case SubmitRequirementStatus.SATISFIED:
+ return 'check';
+ case SubmitRequirementStatus.UNSATISFIED:
+ return 'close';
+ case SubmitRequirementStatus.OVERRIDDEN:
+ return 'warning';
+ case SubmitRequirementStatus.NOT_APPLICABLE:
+ return 'info';
+ default:
+ assertNever(status, `Unsupported status: ${status}`);
+ }
+}
diff --git a/polygerrit-ui/app/utils/label-util_test.ts b/polygerrit-ui/app/utils/label-util_test.ts
index 56941ba..196c5e9 100644
--- a/polygerrit-ui/app/utils/label-util_test.ts
+++ b/polygerrit-ui/app/utils/label-util_test.ts
@@ -17,6 +17,7 @@
import '../test/common-test-setup-karma';
import {
+ extractAssociatedLabels,
getApprovalInfo,
getLabelStatus,
getMaxAccounts,
@@ -32,6 +33,10 @@
ApprovalInfo,
DetailedLabelInfo,
} from '../types/common';
+import {
+ createSubmitRequirementExpressionInfo,
+ createSubmitRequirementResultInfo,
+} from '../test/test-data-generators';
const VALUES_0 = {
'0': 'neutral',
@@ -186,4 +191,38 @@
labelInfo = {all: [{value: 0}, {value: -2}]};
assert.equal(getRepresentativeValue(labelInfo), -2);
});
+
+ suite('extractAssociatedLabels()', () => {
+ function createSubmitRequirementExpressionInfoWith(expression: string) {
+ return {
+ ...createSubmitRequirementResultInfo(),
+ submittability_expression_result: {
+ ...createSubmitRequirementExpressionInfo(),
+ expression,
+ },
+ };
+ }
+
+ test('1 label', () => {
+ const submitRequirement = createSubmitRequirementExpressionInfoWith(
+ 'label:Verified=MAX -label:Verified=MIN'
+ );
+ const labels = extractAssociatedLabels(submitRequirement);
+ assert.deepEqual(labels, ['Verified']);
+ });
+ test('label with number', () => {
+ const submitRequirement = createSubmitRequirementExpressionInfoWith(
+ 'label2:verified=MAX'
+ );
+ const labels = extractAssociatedLabels(submitRequirement);
+ assert.deepEqual(labels, ['verified']);
+ });
+ test('2 labels', () => {
+ const submitRequirement = createSubmitRequirementExpressionInfoWith(
+ 'label:Verified=MAX -label:Code-Review=MIN'
+ );
+ const labels = extractAssociatedLabels(submitRequirement);
+ assert.deepEqual(labels, ['Verified', 'Code-Review']);
+ });
+ });
});
diff --git a/polygerrit-ui/app/yarn.lock b/polygerrit-ui/app/yarn.lock
index ca04edf..395ef64 100644
--- a/polygerrit-ui/app/yarn.lock
+++ b/polygerrit-ui/app/yarn.lock
@@ -2,6 +2,11 @@
# yarn lockfile v1
+"@lit/reactive-element@^1.0.0-rc.2":
+ version "1.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/@lit/reactive-element/-/reactive-element-1.0.0-rc.3.tgz#5032f493fbf39781b187a7e2dd5d256537c8760c"
+ integrity sha512-Rs2px1keOQUNJUo5B+WExl5v244ZNCiN/iMVNO9evFdJjAdWCIupR/p14zRPkNHsciRBELLTcOZ379cI9O6PDg==
+
"@mapbox/node-pre-gyp@^1.0.0":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950"
@@ -420,6 +425,11 @@
resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.6.tgz#d8e6c2f830e2650dc06fe74464472ff64b54a302"
integrity sha512-61IfTac0s9jvNtBCpyo86QeaN8qqpMGHdK0uGKCCIy2dt5/Yk84VduHIdWAcmkC5QvdkPL0p5eWYgUZtHKKUVg==
+"@types/trusted-types@^1.0.1":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-1.0.6.tgz#569b8a08121d3203398290d602d84d73c8dcf5da"
+ integrity sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw==
+
"@webcomponents/shadycss@^1.10.2", "@webcomponents/shadycss@^1.9.1":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.11.0.tgz#73e289996c002d8be694cd3be0e83c46ad25e7e0"
@@ -642,17 +652,29 @@
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-lit-element@^2.5.1:
- version "2.5.1"
- resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-2.5.1.tgz#3fa74b121a6cd22902409ae3859b7847d01aa6b6"
- integrity sha512-ogu7PiJTA33bEK0xGu1dmaX5vhcRjBXCFexPja0e7P7jqLhTpNKYRPmE+GmiCaRVAbiQKGkUgkh/i6+bh++dPQ==
+lit-element@^3.0.0-rc.2:
+ version "3.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.0.0-rc.3.tgz#cece8f092d28eb6f9c6b23e4138ff5d7260897ef"
+ integrity sha512-NDe7yjW18gfYQb1GIEQr1T8sB1GUAb1HB62pdAEw+SK6lUW7OFPKQqCOlRhZ6qJXsw9KxMnyYIprLZT4FZdYdQ==
dependencies:
- lit-html "^1.1.1"
+ "@lit/reactive-element" "^1.0.0-rc.2"
+ lit-html "^2.0.0-rc.4"
-lit-html@^1.1.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-1.4.1.tgz#0c6f3ee4ad4eb610a49831787f0478ad8e9ae5e0"
- integrity sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA==
+lit-html@^2.0.0-rc.4:
+ version "2.0.0-rc.4"
+ resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.0.0-rc.4.tgz#1015fa8f1f7c8c5b79999ed0bc11c3b79ff1aab5"
+ integrity sha512-WSLGu3vxq7y8q/oOd9I3zxyBELNLLiDk6gAYoKK4PGctI5fbh6lhnO/jVBdy0PV/vTc+cLJCA/occzx3YoNPeg==
+ dependencies:
+ "@types/trusted-types" "^1.0.1"
+
+lit@2.0.0-rc.3:
+ version "2.0.0-rc.3"
+ resolved "https://registry.yarnpkg.com/lit/-/lit-2.0.0-rc.3.tgz#8b6a85268aba287c11125dfe57e88e0bc09beaff"
+ integrity sha512-UZDLWuspl7saA+WvS0e+TE3NdGGE05hOIwUPTWiibs34c5QupcEzpjB/aElt79V9bELQVNbUUwa0Ow7D1Wuszw==
+ dependencies:
+ "@lit/reactive-element" "^1.0.0-rc.2"
+ lit-element "^3.0.0-rc.2"
+ lit-html "^2.0.0-rc.4"
lru-cache@^6.0.0:
version "6.0.0"
diff --git a/polygerrit-ui/karma.conf.js b/polygerrit-ui/karma.conf.js
index fe3fa0c..a3b694f 100644
--- a/polygerrit-ui/karma.conf.js
+++ b/polygerrit-ui/karma.conf.js
@@ -22,6 +22,7 @@
if(runUnderBazel) {
// Run under bazel
return [
+ `external/plugins_npm/node_modules`,
`external/ui_npm/node_modules`,
`external/ui_dev_npm/node_modules`
];
@@ -58,20 +59,34 @@
}
module.exports = function(config) {
- const localDirName = path.resolve(__dirname, '../.ts-out/polygerrit-ui/app');
- const rootDir = runUnderBazel ?
- 'polygerrit-ui/app/_pg_with_tests_out/' : localDirName + '/';
- const testFilesLocationPattern =
- `${rootDir}**/!(template_test_srcs)/`;
+ let root = config.root;
+ if (!root) {
+ console.warn(`--root argument not set. Falling back to __dirname.`)
+ root = path.resolve(__dirname) + '/';
+ }
// Use --test-files to specify pattern for a test files.
// It can be just a file name, without a path:
// --test-files async-foreach-behavior_test.js
// If you specify --test-files without pattern, it gets true value
- // In this case we ill run all tests (usefull for package.json "debugtest"
+ // In this case we will run all tests (usefull for package.json "debugtest"
// script)
- const testFilesPattern = (typeof config.testFiles == 'string') ?
- testFilesLocationPattern + config.testFiles :
- testFilesLocationPattern + '*_test.js';
+ // We will convert a .ts argument to .js and fill in .js if no extension is
+ // given.
+ let filePattern;
+ if (typeof config.testFiles === "string") {
+ if (config.testFiles.endsWith('.ts')) {
+ filePattern = config.testFiles.substr(0, config.testFiles.lastIndexOf(".")) + ".js";
+ } else if (config.testFiles.endsWith('.js')) {
+ filePattern = config.testFiles;
+ } else {
+ filePattern = config.testFiles + '.js';
+ }
+ } else {
+ filePattern = '*_test.js';
+ }
+ const testFilesPattern = root + '**/' + filePattern;
+
+ console.info(`Karma test file pattern: ${testFilesPattern}`)
// Special patch for grep parameters (see details in the grep-patch-karam.js)
const additionalFiles = runUnderBazel ? [] : ['polygerrit-ui/grep-patch-karma.js'];
config.set({
diff --git a/polygerrit-ui/karma_test.sh b/polygerrit-ui/karma_test.sh
index 5fab442..940b969 100755
--- a/polygerrit-ui/karma_test.sh
+++ b/polygerrit-ui/karma_test.sh
@@ -1,4 +1,6 @@
#!/bin/bash
set -euo pipefail
-./$1 start $2 --single-run
+./$1 start $2 \
+ --root 'polygerrit-ui/app/_pg_with_tests_out/**/' \
+ --test-files '*_test.js'
diff --git a/polygerrit-ui/server.go b/polygerrit-ui/server.go
index ddfaeb4..2a433fb 100644
--- a/polygerrit-ui/server.go
+++ b/polygerrit-ui/server.go
@@ -184,10 +184,10 @@
// 'page/page.mjs' -> '/node_modules/page.mjs'
// '@polymer/iron-icon' -> '/node_modules/@polymer/iron-icon.js'
// './element/file' -> './element/file.js'
- moduleImportRegexp = regexp.MustCompile(`(?m)^(import.*|export.* from )['"](.*?)(\.(m?)js)?['"];$`)
+ moduleImportRegexp = regexp.MustCompile(`(import[^'";]*|export[^'";]*from ?)['"]([^;\s]*?)(\.(m?)js)?['"];`)
data = moduleImportRegexp.ReplaceAll(data, []byte("$1'$2.${4}js';"))
- moduleImportRegexp = regexp.MustCompile(`(?m)^(import.*|export.* from )['"]([^/.].*)['"];$`)
+ moduleImportRegexp = regexp.MustCompile(`(import[^'";]*|export[^'";]*from ?)['"]([^/.;\s][^;\s]*)['"];`)
data = moduleImportRegexp.ReplaceAll(data, []byte("$1'/node_modules/$2';"))
// The es module version of rxjs can be found in the _esm2015/ directory.
@@ -198,9 +198,12 @@
moduleImportRegexp = regexp.MustCompile("(?m)^((import|export).*'/node_modules/)tslib.js';$")
data = moduleImportRegexp.ReplaceAll(data, []byte("${1}tslib/tslib.es6.js';"))
- // 'lit-element' imports and exports have to be resolved to 'lit-element/lit-element.js'.
- moduleImportRegexp = regexp.MustCompile("(?m)^((import|export).*'/node_modules/)lit-(element|html).js';$")
- data = moduleImportRegexp.ReplaceAll(data, []byte("${1}lit-${3}/lit-${3}.js';"))
+ // 'lit.js' has to be resolved as 'lit/index.js'.
+ moduleImportRegexp = regexp.MustCompile("(?m)^((import|export).*'/node_modules/)lit.js';$")
+ data = moduleImportRegexp.ReplaceAll(data, []byte("${1}lit/index.js';"))
+ // Some lit imports 'a.js' have to be resolved as 'a/a.js'.
+ moduleImportRegexp = regexp.MustCompile(`((import|export)[^'";]*'/node_modules/(@lit/)?)(lit-element|lit-html|reactive-element).js';`)
+ data = moduleImportRegexp.ReplaceAll(data, []byte("${1}${4}/${4}.js';"))
// 'immer' imports and exports have to be resolved to 'immer/dist/immer.esm.js'.
moduleImportRegexp = regexp.MustCompile("(?m)^((import|export).*'/node_modules/)immer.js';$")
diff --git a/proto/cache.proto b/proto/cache.proto
index aa04555..16e5e95 100644
--- a/proto/cache.proto
+++ b/proto/cache.proto
@@ -268,13 +268,14 @@
// com.google.gerrit.server.account.externalids.AllExternalIds.
// Next ID: 2
message AllExternalIdsProto {
- // Next ID: 6
+ // Next ID: 7
message ExternalIdProto {
string key = 1;
int32 accountId = 2;
string email = 3;
string password = 4;
bytes blobId = 5;
+ bool isCaseInsensitive = 6;
}
repeated ExternalIdProto external_id = 1;
}
@@ -483,7 +484,7 @@
}
// Serialized form of com.google.gerrit.entities.SubmitRequirementResult.
-// Next ID: 6
+// Next ID: 7
message SubmitRequirementResultProto {
SubmitRequirementProto submit_requirement = 1;
SubmitRequirementExpressionResultProto applicability_expression_result = 2;
@@ -492,6 +493,9 @@
// Patchset commit ID at which the submit requirements are evaluated.
bytes commit = 5;
+
+ // Whether this result was created from a legacy submit record.
+ bool legacy = 6;
}
// Serialized form of com.google.gerrit.entities.SubmitRequirementExpressionResult.
diff --git a/proto/entities.proto b/proto/entities.proto
index d4ff736..de8f647 100644
--- a/proto/entities.proto
+++ b/proto/entities.proto
@@ -133,6 +133,7 @@
optional string tag = 6;
optional Account_Id real_account_id = 7;
optional bool post_submit = 8;
+ optional bool copied = 9;
// Deleted fields, should not be reused:
reserved 4; // changeOpen
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeader.soy b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
index 5dfe671..3d0edab 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeader.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeader.soy
@@ -20,10 +20,10 @@
{@param attentionSet: ?}
{if $attentionSet}
Attention is currently required from:{sp}
- {for $attentionSetUser in $attentionSet}
+ {for $attentionSetUser, $index in $attentionSet}
{$attentionSetUser}
// add commas or dot.
- {if isLast($attentionSetUser)}.
+ {if $index == length($attentionSet) - 1}.
{else},{sp}
{/if}
{/for}
diff --git a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
index 191737f..0d8da38 100644
--- a/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
+++ b/resources/com/google/gerrit/server/mail/ChangeHeaderHtml.soy
@@ -21,10 +21,10 @@
{@param attentionSet: ?}
{if $attentionSet}
<p> Attention is currently required from:{sp}
- {for $attentionSetUser in $attentionSet}
+ {for $attentionSetUser, $index in $attentionSet}
{$attentionSetUser}
//add commas or dot.
- {if isLast($attentionSetUser)}.
+ {if $index == length($attentionSet) - 1}.
{else},{sp}
{/if}
{/for} </p>
diff --git a/resources/com/google/gerrit/server/mail/Comment.soy b/resources/com/google/gerrit/server/mail/Comment.soy
index 4b923e6..4b66401 100644
--- a/resources/com/google/gerrit/server/mail/Comment.soy
+++ b/resources/com/google/gerrit/server/mail/Comment.soy
@@ -48,8 +48,8 @@
{\n}
{/if}
- {for $line in $comment.lines}
- {if isFirst($line)}
+ {for $line, $index in $comment.lines}
+ {if $index == 0}
{if $comment.startLine != 0}
{$comment.link}
{/if}
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
index a3ed3ee..ae2a9c4 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewer.soy
@@ -26,8 +26,8 @@
{@param email: ?}
{@param fromName: ?}
{$fromName} has removed{sp}
- {for $reviewerName in $email.reviewerNames}
- {if not isFirst($reviewerName)},{sp}{/if}
+ {for $reviewerName, $index in $email.reviewerNames}
+ {if $index > 0},{sp}{/if}
{$reviewerName}
{/for}{sp}
from this change.{sp}
diff --git a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
index 76a9199..fdcbbe7 100644
--- a/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
+++ b/resources/com/google/gerrit/server/mail/DeleteReviewerHtml.soy
@@ -25,9 +25,9 @@
{$fromName}{sp}
<strong>
removed{sp}
- {for $reviewerName in $email.reviewerNames}
- {if not isFirst($reviewerName)}
- {if isLast($reviewerName)}{sp}and{else},{/if}{sp}
+ {for $reviewerName, $index in $email.reviewerNames}
+ {if $index > 0}
+ {if $index == (length($email.reviewerNames) - 1)}{sp}and{else},{/if}{sp}
{/if}
{$reviewerName}
{/for}
diff --git a/resources/com/google/gerrit/server/mail/Merged.soy b/resources/com/google/gerrit/server/mail/Merged.soy
index e268a31..b8a19fc 100644
--- a/resources/com/google/gerrit/server/mail/Merged.soy
+++ b/resources/com/google/gerrit/server/mail/Merged.soy
@@ -30,7 +30,7 @@
{if $email.changeUrl} ( {$email.changeUrl} ){/if}{\n}
{\n}
- {$email.stickyApprovalDiff}
+ {if $email.stickyApprovalDiff} ( {$email.stickyApprovalDiff} ){/if}
Change subject: {$change.subject}{\n}
......................................................................{\n}
diff --git a/resources/com/google/gerrit/server/mail/MergedHtml.soy b/resources/com/google/gerrit/server/mail/MergedHtml.soy
index d2f7bfd..ac4afb3 100644
--- a/resources/com/google/gerrit/server/mail/MergedHtml.soy
+++ b/resources/com/google/gerrit/server/mail/MergedHtml.soy
@@ -32,9 +32,11 @@
</p>
{/if}
- {call mailTemplate.UnifiedDiff}
- {param diffLines: $email.stickyApprovalDiffHtml /}
- {/call}
+ {if $email.stickyApprovalDiffHtml}
+ {call mailTemplate.UnifiedDiff}
+ {param diffLines: $email.stickyApprovalDiffHtml /}
+ {/call}
+ {/if}
<div style="white-space:pre-wrap">{$email.approvals}</div>
diff --git a/resources/com/google/gerrit/server/mail/NewChange.soy b/resources/com/google/gerrit/server/mail/NewChange.soy
index aa2b946..c5f34b4 100644
--- a/resources/com/google/gerrit/server/mail/NewChange.soy
+++ b/resources/com/google/gerrit/server/mail/NewChange.soy
@@ -30,8 +30,8 @@
{if $email.reviewerNames or $email.removedReviewerNames}
{if $email.reviewerNames}
Hello{sp}
- {for $reviewerName in $email.reviewerNames}
- {if not isFirst($reviewerName)},{sp}{/if}
+ {for $reviewerName, $index in $email.reviewerNames}
+ {if $index > 0},{sp}{/if}
{$reviewerName}
{/for},
@@ -43,8 +43,8 @@
{/if}
{if $email.removedReviewerNames}
{$fromName} has removed{sp}
- {for $reviewerName in $email.removedReviewerNames}
- {if not isFirst($reviewerName)},{sp}{/if}
+ {for $reviewerName, $index in $email.removedReviewerNames}
+ {if $index > 0},{sp}{/if}
{$reviewerName}
{/for}{sp}
from this change.{sp}
diff --git a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
index 272c3ef..008226f 100644
--- a/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
+++ b/resources/com/google/gerrit/server/mail/NewChangeHtml.soy
@@ -29,9 +29,9 @@
{if $email.reviewerNames or $email.removedReviewerNames}
{if $email.reviewerNames}
{$fromName} would like{sp}
- {for $reviewerName in $email.reviewerNames}
- {if not isFirst($reviewerName)}
- {if isLast($reviewerName)}{sp}and{else},{/if}{sp}
+ {for $reviewerName, $index in $email.reviewerNames}
+ {if $index > 0}
+ {if $index == length($email.reviewerNames) - 1}{sp}and{else},{/if}{sp}
{/if}
{$reviewerName}
{/for}{sp}
@@ -44,9 +44,9 @@
{$fromName}{sp}
<strong>
removed{sp}
- {for $reviewerName in $email.removedReviewerNames}
- {if not isFirst($reviewerName)}
- {if isLast($reviewerName)}{sp}and{else},{/if}{sp}
+ {for $reviewerName, $index in $email.removedReviewerNames}
+ {if $index > 0}
+ {if $index == length($email.removedReviewerNames) - 1}{sp}and{else},{/if}{sp}
{/if}
{$reviewerName}
{/for}
diff --git a/tools/BUILD b/tools/BUILD
index 545a206..1bace53 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -68,77 +68,398 @@
# Error Prone errors enabled by default; see ../.bazelrc for how this is
# enabled. This warnings list is originally based on:
# https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl
+# Additionally, items used internally in google is added. Such items have
+# the same or higher verbosity level than in google.
# However, feel free to add any additional errors. Thus far they have all been pretty useful.
-# TODO(davido): Enable ImmutableAnnotationChecker again when these issues are fixed:
-# https://github.com/google/error-prone/issues/1348
-# https://github.com/bazelbuild/bazel/issues/9378
+# All warnings are commented to avoid noise in the output.
+# Newer versions of error-prone have XepDisableAllWarnings flag which could
+# be used instead of commenting. Bazel should be updated to use a new version
+# of error-prone.
java_package_configuration(
name = "error_prone",
javacopts = [
"-XepDisableWarningsInGeneratedCode",
+ # The XepDisableWarningsInGeneratedCode disables only warnings, but
+ # not errors. We should manually exclude all files generated by
+ # AutoValue; such files always start $AutoValue_.....
+ # XepExcludedPaths is a regexp. If you need more paths - use | as
+ # separator.
+ "-XepExcludedPaths:.*/\\\\$$AutoValue_.*\\.java",
+ "-Xep:AlmostJavadoc:ERROR",
+ "-Xep:AlwaysThrows:ERROR",
"-Xep:AmbiguousMethodReference:ERROR",
+ "-Xep:AnnotateFormatMethod:ERROR",
+ "-Xep:ArgumentSelectionDefectChecker:ERROR",
+ "-Xep:ArrayAsKeyOfSetOrMap:ERROR",
+ "-Xep:ArrayEquals:ERROR",
+ "-Xep:ArrayFillIncompatibleType:ERROR",
+ "-Xep:ArrayHashCode:ERROR",
+ "-Xep:ArrayToString:ERROR",
+ "-Xep:ArraysAsListPrimitiveArray:ERROR",
+ "-Xep:AssertEqualsArgumentOrderChecker:ERROR",
+ "-Xep:AssertionFailureIgnored:ERROR",
+ "-Xep:AsyncCallableReturnsNull:ERROR",
+ "-Xep:AsyncFunctionReturnsNull:ERROR",
+ "-Xep:AutoValueConstructorOrderChecker:ERROR",
"-Xep:AutoValueFinalMethods:ERROR",
+ # "-Xep:AutoValueImmutableFields:WARN",
+ # "-Xep:AutoValueSubclassLeaked:WARN",
"-Xep:BadAnnotationImplementation:ERROR",
"-Xep:BadComparable:ERROR",
+ # "-Xep:BadImport:WARN",
+ "-Xep:BadInstanceof:ERROR",
+ "-Xep:BadShiftAmount:ERROR",
+ "-Xep:BanSerializableRead:ERROR",
+ "-Xep:BigDecimalEquals:ERROR",
+ "-Xep:BigDecimalLiteralDouble:ERROR",
"-Xep:BoxedPrimitiveConstructor:ERROR",
+ "-Xep:BoxedPrimitiveEquality:ERROR",
+ "-Xep:BundleDeserializationCast:ERROR",
+ "-Xep:ByteBufferBackingArray:ERROR",
+ "-Xep:CacheLoaderNull:ERROR",
"-Xep:CannotMockFinalClass:ERROR",
+ "-Xep:CanonicalDuration:ERROR",
+ # "-Xep:CatchAndPrintStackTrace:WARN",
+ "-Xep:CatchFail:ERROR",
+ "-Xep:ChainedAssertionLosesContext:ERROR",
+ "-Xep:ChainingConstructorIgnoresParameter:ERROR",
+ "-Xep:CharacterGetNumericValue:ERROR",
+ "-Xep:CheckNotNullMultipleTimes:ERROR",
+ "-Xep:CheckReturnValue:ERROR",
"-Xep:ClassCanBeStatic:ERROR",
+ "-Xep:ClassName:ERROR",
"-Xep:ClassNewInstance:ERROR",
+ "-Xep:CollectionIncompatibleType:ERROR",
+ "-Xep:CollectionToArraySafeParameter:ERROR",
+ "-Xep:CollectionUndefinedEquality:ERROR",
+ "-Xep:CollectorShouldNotUseState:ERROR",
+ "-Xep:ComparableAndComparator:ERROR",
+ "-Xep:ComparableType:ERROR",
+ "-Xep:CompareToZero:ERROR",
+ "-Xep:ComparingThisWithNull:ERROR",
+ "-Xep:ComparisonOutOfRange:ERROR",
+ "-Xep:CompatibleWithAnnotationMisuse:ERROR",
+ "-Xep:CompileTimeConstant:ERROR",
+ "-Xep:ComplexBooleanConstant:ERROR",
+ "-Xep:ComputeIfAbsentAmbiguousReference:ERROR",
+ "-Xep:ConditionalExpressionNumericPromotion:ERROR",
+ "-Xep:ConstantOverflow:ERROR",
+ "-Xep:DaggerProvidesNull:ERROR",
+ "-Xep:DangerousLiteralNull:ERROR",
+ "-Xep:DateChecker:ERROR",
"-Xep:DateFormatConstant:ERROR",
+ "-Xep:DeadException:ERROR",
+ "-Xep:DeadThread:ERROR",
"-Xep:DefaultCharset:ERROR",
+ # "-Xep:DefaultPackage:WARN",
+ "-Xep:DepAnn:ERROR",
+ "-Xep:DeprecatedVariable:ERROR",
+ "-Xep:DiscardedPostfixExpression:ERROR",
+ "-Xep:DoNotCall:ERROR",
+ "-Xep:DoNotCallSuggester:ERROR",
+ "-Xep:DoNotClaimAnnotations:ERROR",
+ "-Xep:DoNotMock:ERROR",
+ "-Xep:DoNotMockAutoValue:ERROR",
+ "-Xep:DoubleBraceInitialization:ERROR",
"-Xep:DoubleCheckedLocking:ERROR",
- "-Xep:ElementsCountedInLoop:ERROR",
+ "-Xep:DuplicateMapKeys:ERROR",
+ "-Xep:DurationFrom:ERROR",
+ "-Xep:DurationGetTemporalUnit:ERROR",
+ "-Xep:DurationTemporalUnit:ERROR",
+ "-Xep:DurationToLongTimeUnit:ERROR",
+ "-Xep:EmptyBlockTag:ERROR",
+ # "-Xep:EmptyCatch:WARN",
+ "-Xep:EmptySetMultibindingContributions:ERROR",
+ # "-Xep:EqualsGetClass:WARN",
"-Xep:EqualsHashCode:ERROR",
"-Xep:EqualsIncompatibleType:ERROR",
+ "-Xep:EqualsNaN:ERROR",
+ "-Xep:EqualsNull:ERROR",
+ "-Xep:EqualsReference:ERROR",
+ "-Xep:EqualsUnsafeCast:ERROR",
+ "-Xep:EqualsUsingHashCode:ERROR",
+ "-Xep:EqualsWrongThing:ERROR",
+ "-Xep:ErroneousThreadPoolConstructorChecker:ERROR",
+ # "-Xep:EscapedEntity:WARN",
"-Xep:ExpectedExceptionChecker:ERROR",
+ "-Xep:ExtendingJUnitAssert:ERROR",
+ "-Xep:ExtendsAutoValue:ERROR",
+ "-Xep:FallThrough:ERROR",
"-Xep:Finally:ERROR",
+ "-Xep:FloatCast:ERROR",
+ "-Xep:FloatingPointAssertionWithinEpsilon:ERROR",
"-Xep:FloatingPointLiteralPrecision:ERROR",
+ "-Xep:FloggerArgumentToString:ERROR",
+ "-Xep:FloggerFormatString:ERROR",
+ "-Xep:FloggerLogVarargs:ERROR",
+ "-Xep:FloggerSplitLogStatement:ERROR",
+ "-Xep:FloggerStringConcatenation:ERROR",
+ "-Xep:ForOverride:ERROR",
+ "-Xep:FormatString:ERROR",
"-Xep:FormatStringAnnotation:ERROR",
"-Xep:FragmentInjection:ERROR",
"-Xep:FragmentNotInstantiable:ERROR",
+ "-Xep:FromTemporalAccessor:ERROR",
"-Xep:FunctionalInterfaceClash:ERROR",
+ "-Xep:FunctionalInterfaceMethodChanged:ERROR",
"-Xep:FutureReturnValueIgnored:ERROR",
+ "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR",
+ "-Xep:GetClassOnAnnotation:ERROR",
+ "-Xep:GetClassOnClass:ERROR",
"-Xep:GetClassOnEnum:ERROR",
- "-Xep:ImmutableAnnotationChecker:OFF",
+ "-Xep:GuardedBy:ERROR",
+ "-Xep:GuiceAssistedInjectScoping:ERROR",
+ "-Xep:GuiceAssistedParameters:ERROR",
+ "-Xep:HashtableContains:ERROR",
+ "-Xep:HidingField:ERROR",
+ "-Xep:IdentityBinaryExpression:ERROR",
+ "-Xep:IdentityHashMapBoxing:ERROR",
+ "-Xep:IdentityHashMapUsage:ERROR",
+ "-Xep:IgnoredPureGetter:ERROR",
+ "-Xep:Immutable:ERROR",
+ "-Xep:ImmutableAnnotationChecker:ERROR",
"-Xep:ImmutableEnumChecker:ERROR",
+ "-Xep:ImmutableModification:ERROR",
+ "-Xep:Incomparable:ERROR",
+ "-Xep:IncompatibleArgumentType:ERROR",
"-Xep:IncompatibleModifiers:ERROR",
+ # "-Xep:InconsistentCapitalization:WARN",
+ "-Xep:InconsistentHashCode:ERROR",
+ "-Xep:IncrementInForLoopAndHeader:ERROR",
+ "-Xep:IndexOfChar:ERROR",
+ "-Xep:InexactVarargsConditional:ERROR",
+ "-Xep:InfiniteRecursion:ERROR",
"-Xep:InjectOnConstructorOfAbstractClass:ERROR",
+ "-Xep:InheritDoc:ERROR",
+ # "-Xep:InlineFormatString:WARN",
+ "-Xep:InlineMeInliner:ERROR",
+ "-Xep:InlineMeSuggester:ERROR",
+ "-Xep:InlineMeValidator:ERROR",
"-Xep:InputStreamSlowMultibyteRead:ERROR",
+ "-Xep:InsecureCryptoUsage:ERROR",
+ "-Xep:InstanceOfAndCastMatchWrongType:ERROR",
+ "-Xep:InstantTemporalUnit:ERROR",
+ "-Xep:IntLongMath:ERROR",
+ # "-Xep:InvalidBlockTag:WARN",
+ # "-Xep:InvalidInlineTag:WARN",
+ "-Xep:InvalidJavaTimeConstant:ERROR",
+ "-Xep:InvalidLink:ERROR",
+ # "-Xep:InvalidParam:WARN",
+ "-Xep:InvalidPatternSyntax:ERROR",
+ "-Xep:InvalidThrows:ERROR",
+ "-Xep:InvalidThrowsLink:ERROR",
+ "-Xep:InvalidTimeZoneID:ERROR",
+ "-Xep:InvalidZoneId:ERROR",
+ "-Xep:IsInstanceIncompatibleType:ERROR",
+ "-Xep:IsInstanceOfClass:ERROR",
+ "-Xep:IsLoggableTagLength:ERROR",
"-Xep:IterableAndIterator:ERROR",
+ "-Xep:IterablePathParameter:ERROR",
"-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR",
+ "-Xep:JUnit3TestNotRun:ERROR",
+ "-Xep:JUnit4ClassAnnotationNonStatic:ERROR",
+ "-Xep:JUnit4ClassUsedInJUnit3:ERROR",
+ "-Xep:JUnit4SetUpNotRun:ERROR",
+ "-Xep:JUnit4TearDownNotRun:ERROR",
+ "-Xep:JUnit4TestNotRun:ERROR",
+ "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR",
"-Xep:JUnitAmbiguousTestClass:ERROR",
- "-Xep:LiteralClassName:ERROR",
+ "-Xep:JUnitAssertSameCheck:ERROR",
+ "-Xep:JUnitParameterMethodNotFound:ERROR",
+ "-Xep:JavaDurationGetSecondsGetNano:ERROR",
+ "-Xep:JavaDurationWithNanos:ERROR",
+ "-Xep:JavaDurationWithSeconds:ERROR",
+ "-Xep:JavaInstantGetSecondsGetNano:ERROR",
+ # "-Xep:JavaLangClash:WARN",
+ "-Xep:JavaLocalDateTimeGetNano:ERROR",
+ "-Xep:JavaLocalTimeGetNano:ERROR",
+ "-Xep:JavaPeriodGetDays:ERROR",
+ "-Xep:JavaTimeDefaultTimeZone:ERROR",
+ "-Xep:JavaUtilDate:ERROR",
+ # "-Xep:JdkObsolete:WARN",
+ "-Xep:JodaConstructors:ERROR",
+ "-Xep:JodaDateTimeConstants:ERROR",
+ "-Xep:JodaDurationWithMillis:ERROR",
+ "-Xep:JodaInstantWithMillis:ERROR",
+ "-Xep:JodaNewPeriod:ERROR",
+ "-Xep:JodaPlusMinusLong:ERROR",
+ "-Xep:JodaTimeConverterManager:ERROR",
+ "-Xep:JodaToSelf:ERROR",
+ "-Xep:JodaWithDurationAddedLong:ERROR",
+ "-Xep:LiteByteStringUtf8:ERROR",
+ "-Xep:LiteEnumValueOf:ERROR",
+ "-Xep:LiteProtoToString:ERROR",
+ "-Xep:LocalDateTemporalAmount:ERROR",
+ "-Xep:LockNotBeforeTry:ERROR",
+ "-Xep:LockOnBoxedPrimitive:ERROR",
+ "-Xep:LogicalAssignment:ERROR",
+ "-Xep:LongFloatConversion:ERROR",
+ "-Xep:LongLiteralLowerCaseSuffix:ERROR",
+ "-Xep:LoopConditionChecker:ERROR",
+ "-Xep:LoopOverCharArray:ERROR",
+ "-Xep:LossyPrimitiveCompare:ERROR",
+ "-Xep:MathAbsoluteRandom:ERROR",
+ "-Xep:MathRoundIntLong:ERROR",
+ "-Xep:MemoizeConstantVisitorStateLookups:ERROR",
+ "-Xep:MislabeledAndroidString:ERROR",
"-Xep:MissingCasesInEnumSwitch:ERROR",
"-Xep:MissingFail:ERROR",
"-Xep:MissingOverride:ERROR",
+ "-Xep:MissingSummary:ERROR",
+ "-Xep:MissingSuperCall:ERROR",
+ "-Xep:MissingTestCall:ERROR",
+ "-Xep:MisusedDayOfYear:ERROR",
+ "-Xep:MisusedWeekYear:ERROR",
+ "-Xep:MixedDescriptors:ERROR",
+ # "-Xep:MixedMutabilityReturnType:WARN",
+ "-Xep:MockitoUsage:ERROR",
+ "-Xep:ModifiedButNotUsed:ERROR",
+ "-Xep:ModifyCollectionInEnhancedForLoop:ERROR",
+ "-Xep:ModifySourceCollectionInStream:ERROR",
+ "-Xep:ModifyingCollectionWithItself:ERROR",
+ "-Xep:MultipleParallelOrSequentialCalls:ERROR",
+ "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR",
+ "-Xep:MustBeClosedChecker:ERROR",
"-Xep:MutableConstantField:ERROR",
+ # "-Xep:MutablePublicArray:WARN",
+ "-Xep:NCopiesOfChar:ERROR",
"-Xep:NarrowingCompoundAssignment:ERROR",
+ "-Xep:NestedInstanceOfConditions:ERROR",
"-Xep:NonAtomicVolatileUpdate:ERROR",
+ "-Xep:NonCanonicalStaticImport:ERROR",
+ # "-Xep:NonCanonicalType:WARN",
+ "-Xep:NonFinalCompileTimeConstant:ERROR",
"-Xep:NonOverridingEquals:ERROR",
+ "-Xep:NonRuntimeAnnotation:ERROR",
+ "-Xep:NullOptional:ERROR",
+ "-Xep:NullTernary:ERROR",
"-Xep:NullableConstructor:ERROR",
"-Xep:NullablePrimitive:ERROR",
+ "-Xep:NullablePrimitiveArray:ERROR",
"-Xep:NullableVoid:ERROR",
+ "-Xep:ObjectEqualsForPrimitives:ERROR",
"-Xep:ObjectToString:ERROR",
+ "-Xep:ObjectsHashCodePrimitive:ERROR",
"-Xep:OperatorPrecedence:ERROR",
+ "-Xep:OptionalEquality:ERROR",
+ "-Xep:OptionalMapToOptional:ERROR",
+ "-Xep:OptionalMapUnusedValue:ERROR",
+ "-Xep:OptionalNotPresent:ERROR",
+ "-Xep:OptionalOfRedundantMethod:ERROR",
+ "-Xep:OrphanedFormatString:ERROR",
+ "-Xep:OutlineNone:ERROR",
+ "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR",
+ "-Xep:OverrideThrowableToString:ERROR",
+ "-Xep:Overrides:ERROR",
"-Xep:OverridesGuiceInjectableMethod:ERROR",
+ "-Xep:OverridesJavaxInjectableMethod:ERROR",
+ "-Xep:PackageInfo:ERROR",
+ # "-Xep:ParameterName:WARN",
+ "-Xep:ParametersButNotParameterized:ERROR",
+ "-Xep:ParcelableCreator:ERROR",
+ "-Xep:PeriodFrom:ERROR",
+ "-Xep:PeriodGetTemporalUnit:ERROR",
+ "-Xep:PeriodTimeMath:ERROR",
+ "-Xep:PreconditionsCheckNotNullRepeated:ERROR",
"-Xep:PreconditionsInvalidPlaceholder:ERROR",
- "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR",
+ "-Xep:PrimitiveAtomicReference:ERROR",
+ "-Xep:PrivateSecurityContractProtoAccess:ERROR",
+ # "-Xep:ProtectedMembersInFinalClass:WARN",
+ "-Xep:ProtoBuilderReturnValueIgnored:ERROR",
+ "-Xep:ProtoDurationGetSecondsGetNano:ERROR",
+ "-Xep:ProtoFieldNullComparison:ERROR",
+ "-Xep:ProtoRedundantSet:ERROR",
+ "-Xep:ProtoStringFieldReferenceEquality:ERROR",
+ "-Xep:ProtoTimestampGetSecondsGetNano:ERROR",
+ "-Xep:ProtoTruthMixedDescriptors:ERROR",
"-Xep:ProtocolBufferOrdinal:ERROR",
+ "-Xep:ProvidesMethodOutsideOfModule:ERROR",
+ "-Xep:RandomCast:ERROR",
+ "-Xep:RandomModInteger:ERROR",
+ "-Xep:ReachabilityFenceUsage:ERROR",
+ "-Xep:RectIntersectReturnValueIgnored:ERROR",
"-Xep:ReferenceEquality:ERROR",
+ "-Xep:RefersToDaggerCodegen:ERROR",
+ "-Xep:RemovedInJDK11:ERROR",
"-Xep:RequiredModifiers:ERROR",
+ "-Xep:RestrictedApiChecker:ERROR",
+ "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR",
+ "-Xep:ReturnFromVoid:ERROR",
+ "-Xep:ReturnValueIgnored:ERROR",
+ "-Xep:RxReturnValueIgnored:ERROR",
+ # "-Xep:SameNameButDifferent:WARN",
+ "-Xep:SelfAssignment:ERROR",
+ "-Xep:SelfComparison:ERROR",
+ "-Xep:SelfEquals:ERROR",
"-Xep:ShortCircuitBoolean:ERROR",
- "-Xep:SimpleDateFormatConstant:ERROR",
+ "-Xep:ShouldHaveEvenArgs:ERROR",
+ "-Xep:SizeGreaterThanOrEqualsZero:ERROR",
+ "-Xep:StaticAssignmentInConstructor:ERROR",
"-Xep:StaticGuardedByInstance:ERROR",
+ "-Xep:StaticMockMember:ERROR",
+ "-Xep:StaticQualifiedUsingExpression:ERROR",
+ "-Xep:StreamToString:ERROR",
+ "-Xep:StringBuilderInitWithChar:ERROR",
"-Xep:StringEquality:ERROR",
+ # "-Xep:StringSplitter:WARN",
+ "-Xep:SubstringOfZero:ERROR",
+ "-Xep:SuppressWarningsDeprecated:ERROR",
+ "-Xep:SwigMemoryLeak:ERROR",
"-Xep:SynchronizeOnNonFinalField:ERROR",
+ "-Xep:TemporalAccessorGetChronoField:ERROR",
+ "-Xep:TestParametersNotInitialized:ERROR",
+ "-Xep:TheoryButNoTheories:ERROR",
+ # "-Xep:ThreadJoinLoop:WARN",
+ "-Xep:ThreadLocalUsage:ERROR",
+ # "-Xep:ThreadPriorityCheck:WARN",
+ "-Xep:ThreeLetterTimeZoneID:ERROR",
+ "-Xep:ThrowIfUncheckedKnownChecked:ERROR",
+ "-Xep:ThrowNull:ERROR",
+ "-Xep:TimeUnitConversionChecker:ERROR",
+ "-Xep:ToStringReturnsNull:ERROR",
+ "-Xep:TreeToString:ERROR",
+ # "-Xep:TruthAssertExpected:WARN",
"-Xep:TruthConstantAsserts:ERROR",
+ "-Xep:TruthGetOrDefault:ERROR",
+ "-Xep:TruthIncompatibleType:ERROR",
+ "-Xep:TruthSelfEquals:ERROR",
+ "-Xep:TryFailThrowable:ERROR",
+ "-Xep:TypeEquals:ERROR",
+ "-Xep:TypeNameShadowing:ERROR",
+ "-Xep:TypeParameterQualifier:ERROR",
"-Xep:TypeParameterShadowing:ERROR",
"-Xep:TypeParameterUnusedInFormals:ERROR",
"-Xep:URLEqualsHashCode:ERROR",
+ # "-Xep:UndefinedEquals:WARN",
+ "-Xep:UnescapedEntity:ERROR",
+ "-Xep:UnnecessaryAssignment:ERROR",
+ "-Xep:UnnecessaryCheckNotNull:ERROR",
+ # "-Xep:UnnecessaryLambda:WARN",
+ "-Xep:UnnecessaryMethodInvocationMatcher:ERROR",
+ "-Xep:UnnecessaryMethodReference:ERROR",
+ # "-Xep:UnnecessaryParentheses:WARN",
+ "-Xep:UnnecessaryTypeArgument:ERROR",
+ "-Xep:UnrecognisedJavadocTag:ERROR",
+ "-Xep:UnsafeFinalization:ERROR",
+ "-Xep:UnsafeReflectiveConstructionCast:ERROR",
"-Xep:UnsynchronizedOverridesSynchronized:ERROR",
+ "-Xep:UnusedAnonymousClass:ERROR",
+ "-Xep:UnusedCollectionModifiedInPlace:ERROR",
"-Xep:UnusedException:ERROR",
+ "-Xep:UnusedMethod:ERROR",
+ "-Xep:UnusedNestedClass:ERROR",
+ "-Xep:UnusedVariable:ERROR",
+ "-Xep:UseBinds:ERROR",
+ "-Xep:UseCorrectAssertInTests:ERROR",
+ "-Xep:VarTypeName:ERROR",
+ "-Xep:VariableNameSameAsType:ERROR",
"-Xep:WaitNotInLoop:ERROR",
+ "-Xep:WakelockReleasedDangerously:ERROR",
"-Xep:WildcardImport:ERROR",
+ "-Xep:WithSignatureDiscouraged:ERROR",
+ "-Xep:WrongOneof:ERROR",
+ "-Xep:XorPower:ERROR",
+ "-Xep:ZoneIdOfZ:ERROR",
],
packages = ["error_prone_packages"],
)
diff --git a/tools/bzl/js.bzl b/tools/bzl/js.bzl
index eedf0a1..c8d6e4b 100644
--- a/tools/bzl/js.bzl
+++ b/tools/bzl/js.bzl
@@ -142,3 +142,36 @@
"zip -Drq $$ROOT/$@ -g .",
]),
)
+
+def karma_test(name, srcs, data):
+ """Creates a Karma test target.
+
+ It can be used both for the main Gerrit js bundle, but also for plugins. So
+ it should be extremely easy to add Karma test capabilities for new plugins.
+
+ We are sharing one karma.conf.js file. If you want to customize that, then
+ consider using command line arguments that the config file can process, see
+ the `root` argument for an example.
+
+ Args:
+ name: The name of the test rule.
+ srcs: The shell script to invoke, where you can set command line
+ arguments for Karma and its config.
+ data: The bundle of JavaScript files with the tests included.
+ """
+
+ native.sh_test(
+ name = name,
+ size = "enormous",
+ srcs = srcs,
+ args = [
+ "$(location //polygerrit-ui:karma_bin)",
+ "$(location //polygerrit-ui:karma.conf.js)",
+ ],
+ data = data + [
+ "//polygerrit-ui:karma_bin",
+ "//polygerrit-ui:karma.conf.js",
+ ],
+ # Should not run sandboxed.
+ tags = ["karma", "local", "manual"],
+ )
diff --git a/tools/js/eslint.bzl b/tools/js/eslint.bzl
index b32e2bc..eb4d37a 100644
--- a/tools/js/eslint.bzl
+++ b/tools/js/eslint.bzl
@@ -16,6 +16,34 @@
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "nodejs_test")
+def plugin_eslint():
+ """ Convenience wrapper macro of eslint() for Gerrit js plugins
+
+ Args:
+ name: name of the rule
+ """
+ eslint(
+ name = "lint",
+ srcs = native.glob(["**/*.ts"]),
+ config = ".eslintrc.js",
+ data = [
+ "tsconfig.json",
+ "//plugins:.eslintrc.js",
+ "//plugins:.prettierrc.js",
+ "//plugins:tsconfig-plugins-base.json",
+ ],
+ extensions = [".ts"],
+ ignore = "//plugins:.eslintignore",
+ plugins = [
+ "@npm//eslint-config-google",
+ "@npm//eslint-plugin-html",
+ "@npm//eslint-plugin-import",
+ "@npm//eslint-plugin-jsdoc",
+ "@npm//eslint-plugin-prettier",
+ "@npm//gts",
+ ],
+ )
+
def eslint(name, plugins, srcs, config, ignore, extensions = [".js"], data = []):
""" Macro to define eslint rules for files.
@@ -87,7 +115,7 @@
"*_test_require_patch.js",
"--ignore-pattern",
"*_test_loader.js",
- "./", # Relative to the config file location
+ "./", # Relative to the config file location
],
# Should not run sandboxed.
tags = [
diff --git a/tools/node_tools/launchpad.patch b/tools/node_tools/launchpad.patch
new file mode 100644
index 0000000..565494b
--- /dev/null
+++ b/tools/node_tools/launchpad.patch
@@ -0,0 +1,240 @@
+From d430b5d912bebe87529b887f408ee55c82a0e003 Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Fri, 26 Jun 2020 20:16:47 +0200
+Subject: [PATCH 1/7] Update version.js
+
+---
+ lib/local/version.js | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/version.js b/tools/node_tools/node_modules/launchpad/lib/g/local/version.js
+index 0110a74..2c02bef 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/version.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/version.js
+@@ -6,6 +6,15 @@ var plist = require('plist');
+ var utils = require('./utils');
+ var debug = require('debug')('launchpad:local:version');
+
++var validPath = function (filename){
++ var filter = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/;
++ if (filter.test(filename)){
++ console.log('\nInvalid characters inside the path to the browser\n');
++ return
++ }
++ return filename;
++}
++
+ module.exports = function(browser) {
+ if (!browser || !browser.path) {
+ return Q(null);
+@@ -18,7 +27,7 @@ module.exports = function(browser) {
+
+ debug('Retrieving version for windows executable', command);
+ // Can't use Q.nfcall here unfortunately because of non 0 exit code
+- exec(command, function(error, stdout) {
++ exec(command.split(' ')[0], command.split(' ').slice(1), function(error, stdout) {
+ var regex = /ProductVersion:\s*(.*)/;
+ // ShowVer.exe returns a non zero status code even if it works
+ if (typeof stdout === 'string' && regex.test(stdout)) {
+@@ -47,8 +56,8 @@ module.exports = function(browser) {
+ }
+
+ // Try executing <browser> --version (everything else)
+- return Q.nfcall(exec, browser.path + ' --version').then(function(stdout) {
+- debug('Ran ' + browser.path + ' --version', stdout);
++ return Q.nfcall(exec, validPath(browser.path) + ' --version').then(function(stdout) {
++ debug('Ran ' + validPath(browser.path) + ' --version', stdout);
+ var version = utils.getStdout(stdout);
+ if (version) {
+ browser.version = version;
+
+From 09ce4fab2fd53cab893ceaa3b4d7f997af9b41d8 Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Fri, 26 Jun 2020 20:18:35 +0200
+Subject: [PATCH 2/7] Update instance.js
+
+---
+ lib/local/instance.js | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/instance.js b/tools/node_tools/node_modules/launchpad/lib/g/local/instance.js
+index 484a866..b49990f 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/instance.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/instance.js
+@@ -5,8 +5,15 @@ var EventEmitter = require('events').EventEmitter;
+ var debug = require('debug')('launchpad:local:instance');
+ var rimraf = require('rimraf');
+
++var safe = function (str) {
++ // Avoid quotes makes impossible escape the `multi command` scenario
++ return str.replace(/['"]+/g, '');
++}
++
+ var getProcessId = function (name, callback) {
+
++ name = safe(name);
++
+ var commands = {
+ darwin: "ps -clx | grep '" + name + "$' | awk '{print $2}' | head -1",
+ linux: "ps -ax | grep '" + name + "$' | awk '{print $2}' | head -1",
+@@ -90,11 +97,11 @@ Instance.prototype.stop = function (callback) {
+ } catch (error) {}
+ } else {
+ if (this.options.command.indexOf('open') === 0) {
+- command = 'osascript -e \'tell application "' + self.options.process + '" to quit\'';
++ command = 'osascript -e \'tell application "' + safe(self.options.process) + '" to quit\'';
+ debug('Executing shutdown AppleScript', command);
+ exec(command);
+ } else if (process.platform === 'win32') {
+- command = 'taskkill /IM ' + (this.options.imageName || path.basename(this.cmd));
++ command = 'taskkill /IM "' + safe(this.options.imageName || path.basename(this.cmd)) + '"';
+ debug('Executing shutdown taskkil', command);
+ exec(command).once('exit', function(data) {
+ self.emit('stop', data);
+
+From d3993fce090ed6ef378c1f0594eff18d125dad1e Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Fri, 26 Jun 2020 20:19:17 +0200
+Subject: [PATCH 3/7] Update version.js
+
+---
+ lib/local/version.js | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/version.js b/tools/node_tools/node_modules/launchpad/lib/g/local/version.js
+index 2c02bef..5eac082 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/version.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/version.js
+@@ -6,6 +6,7 @@ var plist = require('plist');
+ var utils = require('./utils');
+ var debug = require('debug')('launchpad:local:version');
+
++// Validate paths supplied by the user in order to avoid "arbitrary command execution"
+ var validPath = function (filename){
+ var filter = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/;
+ if (filter.test(filename)){
+
+From abf3dbcc79e6b338338594ab2dbef834550e8f65 Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Mon, 29 Jun 2020 13:32:50 +0200
+Subject: [PATCH 4/7] Update instance.js
+
+---
+ lib/local/instance.js | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/instance.js b/tools/node_tools/node_modules/launchpad/lib/g/local/instance.js
+index b49990f..9375d1f 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/instance.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/instance.js
+@@ -1,6 +1,7 @@
+ var path = require('path');
+ var spawn = require("child_process").spawn;
+ var exec = require("child_process").exec;
++var execFile = require("child_process").execFile;
+ var EventEmitter = require('events').EventEmitter;
+ var debug = require('debug')('launchpad:local:instance');
+ var rimraf = require('rimraf');
+@@ -99,11 +100,14 @@ Instance.prototype.stop = function (callback) {
+ if (this.options.command.indexOf('open') === 0) {
+ command = 'osascript -e \'tell application "' + safe(self.options.process) + '" to quit\'';
+ debug('Executing shutdown AppleScript', command);
+- exec(command);
++ command = command.split(' ');
++ execFile(command[0], command.slice(1));
+ } else if (process.platform === 'win32') {
+- command = 'taskkill /IM "' + safe(this.options.imageName || path.basename(this.cmd)) + '"';
++ //Adding `"` wasn't safe/functional on Win systems
++ command = 'taskkill /IM ' + (this.options.imageName || path.basename(this.cmd);
+ debug('Executing shutdown taskkil', command);
+- exec(command).once('exit', function(data) {
++ command = command.split(' ');
++ execFile(command[0], command.slice(1)).once('exit', function(data) {
+ self.emit('stop', data);
+ });
+ } else {
+
+From 68518b274c9351f799d41ce85f23499ca4a785e9 Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Tue, 30 Jun 2020 00:01:31 +0200
+Subject: [PATCH 5/7] Update instance.js
+
+---
+ lib/local/instance.js | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/instance.js b/tools/node_tools/node_modules/launchpad/lib/g/local/instance.js
+index 9375d1f..f157dd4 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/instance.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/instance.js
+@@ -104,7 +104,7 @@ Instance.prototype.stop = function (callback) {
+ execFile(command[0], command.slice(1));
+ } else if (process.platform === 'win32') {
+ //Adding `"` wasn't safe/functional on Win systems
+- command = 'taskkill /IM ' + (this.options.imageName || path.basename(this.cmd);
++ command = 'taskkill /IM ' + (this.options.imageName || path.basename(this.cmd));
+ debug('Executing shutdown taskkil', command);
+ command = command.split(' ');
+ execFile(command[0], command.slice(1)).once('exit', function(data) {
+
+From e711d07d40d39162ea4bdb1ed344c58f92bfa10b Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Fri, 3 Jul 2020 12:30:31 +0200
+Subject: [PATCH 6/7] Update version.js
+
+---
+ lib/local/version.js | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/version.js b/tools/node_tools/node_modules/launchpad/lib/g/local/version.js
+index 5eac082..d1403a0 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/version.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/version.js
+@@ -1,5 +1,6 @@
+ var fs = require('fs');
+ var exec = require('child_process').exec;
++var execFile = require('child_process').execFile;
+ var Q = require('q');
+ var path = require('path');
+ var plist = require('plist');
+@@ -8,7 +9,7 @@ var debug = require('debug')('launchpad:local:version');
+
+ // Validate paths supplied by the user in order to avoid "arbitrary command execution"
+ var validPath = function (filename){
+- var filter = /[`!@#$%^&*()_+\-=\[\]{};':"\\|,<>\/?~]/;
++ var filter = /[`!@#$%^&*()_+\-=\[\]{};':"|,<>?~]/;
+ if (filter.test(filename)){
+ console.log('\nInvalid characters inside the path to the browser\n');
+ return
+@@ -28,7 +29,7 @@ module.exports = function(browser) {
+
+ debug('Retrieving version for windows executable', command);
+ // Can't use Q.nfcall here unfortunately because of non 0 exit code
+- exec(command.split(' ')[0], command.split(' ').slice(1), function(error, stdout) {
++ execFile(command.split(' ')[0], command.split(' ').slice(1), function(error, stdout) {
+ var regex = /ProductVersion:\s*(.*)/;
+ // ShowVer.exe returns a non zero status code even if it works
+ if (typeof stdout === 'string' && regex.test(stdout)) {
+
+From a3ff1804f0aacfb4fa20dad1312427b81280bb3e Mon Sep 17 00:00:00 2001
+From: Michele Romano <33063403+Mik317@users.noreply.github.com>
+Date: Fri, 3 Jul 2020 12:31:31 +0200
+Subject: [PATCH 7/7] Update version.js
+
+---
+ lib/local/version.js | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/node_tools/node_modules/launchpad/lib/local/version.js b/tools/node_tools/node_modules/launchpad/lib/g/local/version.js
+index d1403a0..d937be4 100644
+--- a/tools/node_tools/node_modules/launchpad/lib/local/version.js
++++ b/tools/node_tools/node_modules/launchpad/lib/local/version.js
+@@ -9,7 +9,7 @@ var debug = require('debug')('launchpad:local:version');
+
+ // Validate paths supplied by the user in order to avoid "arbitrary command execution"
+ var validPath = function (filename){
+- var filter = /[`!@#$%^&*()_+\-=\[\]{};':"|,<>?~]/;
++ var filter = /[`!@#$%^&*()_+\-=\[\]{};'"|,<>?~]/;
+ if (filter.test(filename)){
+ console.log('\nInvalid characters inside the path to the browser\n');
+ return
diff --git a/tools/node_tools/node_modules_licenses/tsconfig.json b/tools/node_tools/node_modules_licenses/tsconfig.json
index cb7bb60..4a57571 100644
--- a/tools/node_tools/node_modules_licenses/tsconfig.json
+++ b/tools/node_tools/node_modules_licenses/tsconfig.json
@@ -8,8 +8,8 @@
]
}
],
- "target": "es6",
- "module": "commonjs",
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
diff --git a/tools/node_tools/package.json b/tools/node_tools/package.json
index ea36e9f..7ee64df 100644
--- a/tools/node_tools/package.json
+++ b/tools/node_tools/package.json
@@ -19,6 +19,12 @@
"typescript": "4.3.2"
},
"devDependencies": {},
+ "scripts": {
+ "postinstall": "(git apply --reverse --ignore-whitespace launchpad.patch || true) && git apply --ignore-whitespace launchpad.patch"
+ },
"license": "Apache-2.0",
- "private": true
+ "private": true,
+ "resolutions": {
+ "lodash": "4.17.21"
+ }
}
diff --git a/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json b/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json
index 34ffb2f..d3c7d1d 100644
--- a/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json
+++ b/tools/node_tools/polygerrit_app_preprocessor/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
- "target": "es6",
- "module": "commonjs",
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
diff --git a/tools/node_tools/utils/tsconfig.json b/tools/node_tools/utils/tsconfig.json
index 56ab91b..d6bffa0 100644
--- a/tools/node_tools/utils/tsconfig.json
+++ b/tools/node_tools/utils/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
- "target": "es6",
- "module": "commonjs",
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"strict": true,
diff --git a/tools/node_tools/yarn.lock b/tools/node_tools/yarn.lock
index d9a2c93..6525c41 100644
--- a/tools/node_tools/yarn.lock
+++ b/tools/node_tools/yarn.lock
@@ -2,255 +2,262 @@
# yarn lockfile v1
-"@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
- integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.5.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
+ integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
dependencies:
- "@babel/highlight" "^7.8.3"
+ "@babel/highlight" "^7.14.5"
+
+"@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176"
+ integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==
"@babel/core@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.3.tgz#30b0ebb4dd1585de6923a0b4d179e0b9f5d82941"
- integrity sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8"
+ integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==
dependencies:
- "@babel/code-frame" "^7.8.3"
- "@babel/generator" "^7.8.3"
- "@babel/helpers" "^7.8.3"
- "@babel/parser" "^7.8.3"
- "@babel/template" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/code-frame" "^7.14.5"
+ "@babel/generator" "^7.15.0"
+ "@babel/helper-compilation-targets" "^7.15.0"
+ "@babel/helper-module-transforms" "^7.15.0"
+ "@babel/helpers" "^7.14.8"
+ "@babel/parser" "^7.15.0"
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.15.0"
+ "@babel/types" "^7.15.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
- gensync "^1.0.0-beta.1"
- json5 "^2.1.0"
- lodash "^4.17.13"
- resolve "^1.3.2"
- semver "^5.4.1"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.1.2"
+ semver "^6.3.0"
source-map "^0.5.0"
-"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.3.tgz#0e22c005b0a94c1c74eafe19ef78ce53a4d45c03"
- integrity sha512-WjoPk8hRpDRqqzRpvaR8/gDUPkrnOOeuT2m8cNICJtZH6mwaCo3v0OKMI7Y6SM1pBtyijnLtAL0HDi41pf41ug==
+"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15"
+ integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.15.0"
jsesc "^2.5.1"
- lodash "^4.17.13"
source-map "^0.5.0"
-"@babel/helper-annotate-as-pure@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee"
- integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==
+"@babel/helper-annotate-as-pure@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61"
+ integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503"
- integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191"
+ integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==
dependencies:
- "@babel/helper-explode-assignable-expression" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/helper-explode-assignable-expression" "^7.14.5"
+ "@babel/types" "^7.14.5"
-"@babel/helper-call-delegate@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.8.3.tgz#de82619898aa605d409c42be6ffb8d7204579692"
- integrity sha512-6Q05px0Eb+N4/GTyKPPvnkig7Lylw+QzihMpws9iiZQv7ZImf84ZsZpQH7QoWN4n4tm81SnSzPgHw2qtO0Zf3A==
+"@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818"
+ integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==
dependencies:
- "@babel/helper-hoist-variables" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/compat-data" "^7.15.0"
+ "@babel/helper-validator-option" "^7.14.5"
+ browserslist "^4.16.6"
+ semver "^6.3.0"
-"@babel/helper-create-regexp-features-plugin@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz#c774268c95ec07ee92476a3862b75cc2839beb79"
- integrity sha512-Gcsm1OHCUr9o9TcJln57xhWHtdXbA2pgQ58S0Lxlks0WMGNXuki4+GLfX0p+L2ZkINUGZvfkz8rzoqJQSthI+Q==
+"@babel/helper-create-regexp-features-plugin@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4"
+ integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==
dependencies:
- "@babel/helper-regex" "^7.8.3"
- regexpu-core "^4.6.0"
+ "@babel/helper-annotate-as-pure" "^7.14.5"
+ regexpu-core "^4.7.1"
-"@babel/helper-define-map@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15"
- integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==
+"@babel/helper-explode-assignable-expression@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645"
+ integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==
dependencies:
- "@babel/helper-function-name" "^7.8.3"
- "@babel/types" "^7.8.3"
- lodash "^4.17.13"
+ "@babel/types" "^7.14.5"
-"@babel/helper-explode-assignable-expression@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982"
- integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==
+"@babel/helper-function-name@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4"
+ integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==
dependencies:
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/helper-get-function-arity" "^7.14.5"
+ "@babel/template" "^7.14.5"
+ "@babel/types" "^7.14.5"
-"@babel/helper-function-name@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca"
- integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==
+"@babel/helper-get-function-arity@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815"
+ integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==
dependencies:
- "@babel/helper-get-function-arity" "^7.8.3"
- "@babel/template" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-get-function-arity@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
- integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==
+"@babel/helper-hoist-variables@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d"
+ integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-hoist-variables@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134"
- integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==
+"@babel/helper-member-expression-to-functions@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b"
+ integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.15.0"
-"@babel/helper-member-expression-to-functions@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
- integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==
+"@babel/helper-module-imports@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3"
+ integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-module-imports@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
- integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
+"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08"
+ integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/helper-module-imports" "^7.14.5"
+ "@babel/helper-replace-supers" "^7.15.0"
+ "@babel/helper-simple-access" "^7.14.8"
+ "@babel/helper-split-export-declaration" "^7.14.5"
+ "@babel/helper-validator-identifier" "^7.14.9"
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.15.0"
+ "@babel/types" "^7.15.0"
-"@babel/helper-module-transforms@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.8.3.tgz#d305e35d02bee720fbc2c3c3623aa0c316c01590"
- integrity sha512-C7NG6B7vfBa/pwCOshpMbOYUmrYQDfCpVL/JCRu0ek8B5p8kue1+BCXpg2vOYs7w5ACB9GTOBYQ5U6NwrMg+3Q==
+"@babel/helper-optimise-call-expression@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c"
+ integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==
dependencies:
- "@babel/helper-module-imports" "^7.8.3"
- "@babel/helper-simple-access" "^7.8.3"
- "@babel/helper-split-export-declaration" "^7.8.3"
- "@babel/template" "^7.8.3"
- "@babel/types" "^7.8.3"
- lodash "^4.17.13"
+ "@babel/types" "^7.14.5"
-"@babel/helper-optimise-call-expression@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
- integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==
+"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
+ integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
+
+"@babel/helper-remap-async-to-generator@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6"
+ integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==
dependencies:
- "@babel/types" "^7.8.3"
+ "@babel/helper-annotate-as-pure" "^7.14.5"
+ "@babel/helper-wrap-function" "^7.14.5"
+ "@babel/types" "^7.14.5"
-"@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
- integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
-
-"@babel/helper-regex@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965"
- integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==
+"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4"
+ integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==
dependencies:
- lodash "^4.17.13"
+ "@babel/helper-member-expression-to-functions" "^7.15.0"
+ "@babel/helper-optimise-call-expression" "^7.14.5"
+ "@babel/traverse" "^7.15.0"
+ "@babel/types" "^7.15.0"
-"@babel/helper-remap-async-to-generator@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86"
- integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==
+"@babel/helper-simple-access@^7.14.8":
+ version "7.14.8"
+ resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924"
+ integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.8.3"
- "@babel/helper-wrap-function" "^7.8.3"
- "@babel/template" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.8"
-"@babel/helper-replace-supers@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.3.tgz#91192d25f6abbcd41da8a989d4492574fb1530bc"
- integrity sha512-xOUssL6ho41U81etpLoT2RTdvdus4VfHamCuAm4AHxGr+0it5fnwoVdwUJ7GFEqCsQYzJUhcbsN9wB9apcYKFA==
+"@babel/helper-skip-transparent-expression-wrappers@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4"
+ integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==
dependencies:
- "@babel/helper-member-expression-to-functions" "^7.8.3"
- "@babel/helper-optimise-call-expression" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-simple-access@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
- integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==
+"@babel/helper-split-export-declaration@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a"
+ integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==
dependencies:
- "@babel/template" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/types" "^7.14.5"
-"@babel/helper-split-export-declaration@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
- integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==
- dependencies:
- "@babel/types" "^7.8.3"
+"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9":
+ version "7.14.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
+ integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
-"@babel/helper-wrap-function@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610"
- integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==
- dependencies:
- "@babel/helper-function-name" "^7.8.3"
- "@babel/template" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+"@babel/helper-validator-option@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
+ integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
-"@babel/helpers@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.3.tgz#382fbb0382ce7c4ce905945ab9641d688336ce85"
- integrity sha512-LmU3q9Pah/XyZU89QvBgGt+BCsTPoQa+73RxAQh8fb8qkDyIfeQnmgs+hvzhTCKTzqOyk7JTkS3MS1S8Mq5yrQ==
+"@babel/helper-wrap-function@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff"
+ integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==
dependencies:
- "@babel/template" "^7.8.3"
- "@babel/traverse" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/helper-function-name" "^7.14.5"
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.14.5"
+ "@babel/types" "^7.14.5"
-"@babel/highlight@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
- integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==
+"@babel/helpers@^7.14.8":
+ version "7.15.3"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357"
+ integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==
dependencies:
+ "@babel/template" "^7.14.5"
+ "@babel/traverse" "^7.15.0"
+ "@babel/types" "^7.15.0"
+
+"@babel/highlight@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
+ integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.14.5"
chalk "^2.0.0"
- esutils "^2.0.2"
js-tokens "^4.0.0"
-"@babel/parser@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.3.tgz#790874091d2001c9be6ec426c2eed47bc7679081"
- integrity sha512-/V72F4Yp/qmHaTALizEm9Gf2eQHV3QyTL3K0cNfijwnMnb1L+LDlAubb/ZnSdGAVzVSWakujHYs1I26x66sMeQ==
+"@babel/parser@^7.14.5", "@babel/parser@^7.15.0":
+ version "7.15.3"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862"
+ integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==
"@babel/plugin-external-helpers@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.8.3.tgz#5a94164d9af393b2820a3cdc407e28ebf237de4b"
- integrity sha512-mx0WXDDiIl5DwzMtzWGRSPugXi9BxROS05GQrhLNbEamhBiicgn994ibwkyiBH+6png7bm/yA7AUsvHyCXi4Vw==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.14.5.tgz#920baa1569a8df5d5710abc342c7b1ac8968ed76"
+ integrity sha512-q/B/hLX+nDGk73Xn529d7Ar4ih17J8pNBbsXafq8oXij0XfFEA/bks+u+6q5q04zO5o/qivjzui6BqzPfYShEg==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-proposal-async-generator-functions@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
- integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==
+ version "7.14.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz#7028dc4fa21dc199bbacf98b39bab1267d0eaf9a"
+ integrity sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/helper-remap-async-to-generator" "^7.8.3"
- "@babel/plugin-syntax-async-generators" "^7.8.0"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-remap-async-to-generator" "^7.14.5"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
"@babel/plugin-proposal-object-rest-spread@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.8.3.tgz#eb5ae366118ddca67bed583b53d7554cad9951bb"
- integrity sha512-8qvuPwU/xxUCt78HocNlv0mXXo0wdh9VT1R04WU8HGOfaOob26pF+9P5/lYjN/q7DHOX1bvX60hnhOvuQUJdbA==
+ version "7.14.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363"
+ integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+ "@babel/compat-data" "^7.14.7"
+ "@babel/helper-compilation-targets" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.14.5"
-"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.0":
+"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
@@ -265,13 +272,13 @@
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-syntax-import-meta@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.8.3.tgz#230afff79d3ccc215b5944b438e4e266daf3d84d"
- integrity sha512-vYiGd4wQ9gx0Lngb7+bPCwQXGK/PR6FeTIJ+TIOlq+OfOKG/kCAOO2+IBac3oMM9qV7/fU76hfcqxUaLKZf1hQ==
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.10.4"
-"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.0":
+"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
@@ -279,234 +286,244 @@
"@babel/helper-plugin-utils" "^7.8.0"
"@babel/plugin-transform-arrow-functions@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6"
- integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a"
+ integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-async-to-generator@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086"
- integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67"
+ integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==
dependencies:
- "@babel/helper-module-imports" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/helper-remap-async-to-generator" "^7.8.3"
+ "@babel/helper-module-imports" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-remap-async-to-generator" "^7.14.5"
"@babel/plugin-transform-block-scoped-functions@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3"
- integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4"
+ integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-block-scoping@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a"
- integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==
+ version "7.15.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf"
+ integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
- lodash "^4.17.13"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-classes@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.8.3.tgz#46fd7a9d2bb9ea89ce88720477979fe0d71b21b8"
- integrity sha512-SjT0cwFJ+7Rbr1vQsvphAHwUHvSUPmMjMU/0P59G8U2HLFqSa082JO7zkbDNWs9kH/IUqpHI6xWNesGf8haF1w==
+ version "7.14.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz#2a391ffb1e5292710b00f2e2c210e1435e7d449f"
+ integrity sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.8.3"
- "@babel/helper-define-map" "^7.8.3"
- "@babel/helper-function-name" "^7.8.3"
- "@babel/helper-optimise-call-expression" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/helper-replace-supers" "^7.8.3"
- "@babel/helper-split-export-declaration" "^7.8.3"
+ "@babel/helper-annotate-as-pure" "^7.14.5"
+ "@babel/helper-function-name" "^7.14.5"
+ "@babel/helper-optimise-call-expression" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-replace-supers" "^7.14.5"
+ "@babel/helper-split-export-declaration" "^7.14.5"
globals "^11.1.0"
"@babel/plugin-transform-computed-properties@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b"
- integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f"
+ integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-destructuring@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.3.tgz#20ddfbd9e4676906b1056ee60af88590cc7aaa0b"
- integrity sha512-H4X646nCkiEcHZUZaRkhE2XVsoz0J/1x3VVujnn96pSoGCtKPA99ZZA+va+gK+92Zycd6OBKCD8tDb/731bhgQ==
+ version "7.14.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576"
+ integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-duplicate-keys@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1"
- integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954"
+ integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-exponentiation-operator@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7"
- integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493"
+ integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==
dependencies:
- "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-for-of@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.8.3.tgz#15f17bce2fc95c7d59a24b299e83e81cedc22e18"
- integrity sha512-ZjXznLNTxhpf4Q5q3x1NsngzGA38t9naWH8Gt+0qYZEJAcvPI9waSStSh56u19Ofjr7QmD0wUsQ8hw8s/p1VnA==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb"
+ integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-function-name@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b"
- integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2"
+ integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==
dependencies:
- "@babel/helper-function-name" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-function-name" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-instanceof@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.8.3.tgz#a44d7d71590da36be7429573300618aefd784c3d"
- integrity sha512-c/jB6Ebe2u17hxo+rce6PDgbkuHyfcJOleqgHYttnvMrCsxVwUnYsMq7GhxXekzUQsv9IImhv6YICKihpen+Ag==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.14.5.tgz#8568277fbcfd7a3e4f3e6c8b7aa8ce4f60cba6e7"
+ integrity sha512-3CIpRzBLk5tEwIzjjD86KR8oMYrp1fl9q7kbdJa6O6Lcmkcee9DXfeO6zRXis//5gWRf63o5oDlNBh0VAlmtgw==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-literals@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1"
- integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78"
+ integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-modules-amd@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.8.3.tgz#65606d44616b50225e76f5578f33c568a0b876a5"
- integrity sha512-MadJiU3rLKclzT5kBH4yxdry96odTUwuqrZM+GllFI/VhxfPz+k9MshJM+MwhfkCdxxclSbSBbUGciBngR+kEQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7"
+ integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==
dependencies:
- "@babel/helper-module-transforms" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
- babel-plugin-dynamic-import-node "^2.3.0"
+ "@babel/helper-module-transforms" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ babel-plugin-dynamic-import-node "^2.3.3"
"@babel/plugin-transform-object-super@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725"
- integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45"
+ integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/helper-replace-supers" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-replace-supers" "^7.14.5"
-"@babel/plugin-transform-parameters@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.8.3.tgz#7890576a13b17325d8b7d44cb37f21dc3bbdda59"
- integrity sha512-/pqngtGb54JwMBZ6S/D3XYylQDFtGjWrnoCF4gXZOUpFV/ujbxnoNGNvDGu6doFWRPBveE72qTx/RRU44j5I/Q==
+"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3"
+ integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==
dependencies:
- "@babel/helper-call-delegate" "^7.8.3"
- "@babel/helper-get-function-arity" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-regenerator@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.3.tgz#b31031e8059c07495bf23614c97f3d9698bc6ec8"
- integrity sha512-qt/kcur/FxrQrzFR432FGZznkVAjiyFtCOANjkAKwCbt465L6ZCiUQh2oMYGU3Wo8LRFJxNDFwWn106S5wVUNA==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f"
+ integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==
dependencies:
- regenerator-transform "^0.14.0"
+ regenerator-transform "^0.14.2"
"@babel/plugin-transform-shorthand-properties@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8"
- integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58"
+ integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-spread@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8"
- integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==
+ version "7.14.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144"
+ integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
"@babel/plugin-transform-sticky-regex@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100"
- integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9"
+ integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
- "@babel/helper-regex" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-template-literals@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80"
- integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93"
+ integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==
dependencies:
- "@babel/helper-annotate-as-pure" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-typeof-symbol@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.3.tgz#5cffb216fb25c8c64ba6bf5f76ce49d3ab079f4d"
- integrity sha512-3TrkKd4LPqm4jHs6nPtSDI/SV9Cm5PRJkHLUgTcqRQQTMAZ44ZaAdDZJtvWFSaRcvT0a1rTmJ5ZA5tDKjleF3g==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4"
+ integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==
dependencies:
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-unicode-regex@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad"
- integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e"
+ integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==
dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.8.3"
- "@babel/helper-plugin-utils" "^7.8.3"
+ "@babel/helper-create-regexp-features-plugin" "^7.14.5"
+ "@babel/helper-plugin-utils" "^7.14.5"
-"@babel/template@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
- integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==
+"@babel/runtime@^7.8.4":
+ version "7.15.3"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
+ integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
dependencies:
- "@babel/code-frame" "^7.8.3"
- "@babel/parser" "^7.8.3"
- "@babel/types" "^7.8.3"
+ regenerator-runtime "^0.13.4"
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.3.tgz#a826215b011c9b4f73f3a893afbc05151358bf9a"
- integrity sha512-we+a2lti+eEImHmEXp7bM9cTxGzxPmBiVJlLVD+FuuQMeeO7RaDbutbgeheDkw+Xe3mCfJHnGOWLswT74m2IPg==
+"@babel/template@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
+ integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==
dependencies:
- "@babel/code-frame" "^7.8.3"
- "@babel/generator" "^7.8.3"
- "@babel/helper-function-name" "^7.8.3"
- "@babel/helper-split-export-declaration" "^7.8.3"
- "@babel/parser" "^7.8.3"
- "@babel/types" "^7.8.3"
+ "@babel/code-frame" "^7.14.5"
+ "@babel/parser" "^7.14.5"
+ "@babel/types" "^7.14.5"
+
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98"
+ integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==
+ dependencies:
+ "@babel/code-frame" "^7.14.5"
+ "@babel/generator" "^7.15.0"
+ "@babel/helper-function-name" "^7.14.5"
+ "@babel/helper-hoist-variables" "^7.14.5"
+ "@babel/helper-split-export-declaration" "^7.14.5"
+ "@babel/parser" "^7.15.0"
+ "@babel/types" "^7.15.0"
debug "^4.1.0"
globals "^11.1.0"
- lodash "^4.17.13"
-"@babel/types@^7.0.0-beta.42", "@babel/types@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
- integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
+"@babel/types@^7.0.0-beta.42", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0":
+ version "7.15.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd"
+ integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==
dependencies:
- esutils "^2.0.2"
- lodash "^4.17.13"
+ "@babel/helper-validator-identifier" "^7.14.9"
to-fast-properties "^2.0.0"
"@bazel/rollup@^3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.5.0.tgz#3de2db08cbc62c3cffbbabaa4517ec250cf6419a"
- integrity sha512-sFPqbzSbIn6h66uuZdXgK5oitSmEGtnDPfL3TwTS4ZWy75SpYvk9X1TFGlvkralEkVnFfdH15sq80/1t+YgQow==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.8.0.tgz#850f56176d73e3b7d99a43c7e33df21ecc6ac161"
+ integrity sha512-u63ubqYtfQhOu8Km3uYdhKa6qiLSlOKYsWwMP1xGkkXzu1hOiUznN1N7q8gCF1BV2DMy1D5IYkv+Xg4a+LEiBA==
"@bazel/typescript@^3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.5.0.tgz#605493f4f0a5297df8a7fcccb86a1a80ea2090bb"
- integrity sha512-BtGFp4nYFkQTmnONCzomk7dkmOwaINBL3piq+lykBlcc6UxLe9iCAnZpOyPypB1ReN3k3SRNAa53x6oGScQxMg==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.8.0.tgz#725d51a1c25e314a1d8cddb8b880ac05ba97acd4"
+ integrity sha512-4C1pLe4V7aidWqcPsWNqXFS7uHAB1nH5SUKG5uWoVv4JT9XhkNSvzzQIycMwXs2tZeCylX4KYNeNvfKrmkyFlw==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
source-map-support "0.5.9"
tsutils "2.27.2"
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31"
+ integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -521,50 +538,85 @@
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@octokit/auth-token@^2.4.0":
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
+ integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
+ dependencies:
+ "@octokit/types" "^6.0.3"
+
+"@octokit/endpoint@^6.0.1":
+ version "6.0.12"
+ resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658"
+ integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==
+ dependencies:
+ "@octokit/types" "^6.0.3"
+ is-plain-object "^5.0.0"
+ universal-user-agent "^6.0.0"
+
+"@octokit/openapi-types@^10.0.0":
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-10.0.0.tgz#db4335de99509021f501fc4e026e6ff495fe1e62"
+ integrity sha512-k1iO2zKuEjjRS1EJb4FwSLk+iF6EGp+ZV0OMRViQoWhQ1fZTk9hg1xccZII5uyYoiqcbC73MRBmT45y1vp2PPg==
+
+"@octokit/plugin-paginate-rest@^1.1.1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc"
+ integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==
+ dependencies:
+ "@octokit/types" "^2.0.1"
+
+"@octokit/plugin-request-log@^1.0.0":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85"
+ integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==
+
+"@octokit/plugin-rest-endpoint-methods@2.4.0":
version "2.4.0"
- resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f"
- integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg==
+ resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e"
+ integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==
dependencies:
- "@octokit/types" "^2.0.0"
+ "@octokit/types" "^2.0.1"
+ deprecation "^2.3.1"
-"@octokit/endpoint@^5.5.0":
- version "5.5.1"
- resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.1.tgz#2eea81e110ca754ff2de11c79154ccab4ae16b3f"
- integrity sha512-nBFhRUb5YzVTCX/iAK1MgQ4uWo89Gu0TH00qQHoYRCsE12dWcG1OiLd7v2EIo2+tpUKPMOQ62QFy9hy9Vg2ULg==
+"@octokit/request-error@^1.0.2":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801"
+ integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==
dependencies:
"@octokit/types" "^2.0.0"
- is-plain-object "^3.0.0"
- universal-user-agent "^4.0.0"
+ deprecation "^2.0.0"
+ once "^1.4.0"
-"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2":
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.0.tgz#a64d2a9d7a13555570cd79722de4a4d76371baaa"
- integrity sha512-DNBhROBYjjV/I9n7A8kVkmQNkqFAMem90dSxqvPq57e2hBr7mNTX98y3R2zDpqMQHVRpBDjsvsfIGgBzy+4PAg==
+"@octokit/request-error@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677"
+ integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==
dependencies:
- "@octokit/types" "^2.0.0"
+ "@octokit/types" "^6.0.3"
deprecation "^2.0.0"
once "^1.4.0"
"@octokit/request@^5.2.0":
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.1.tgz#3a1ace45e6f88b1be4749c5da963b3a3b4a2f120"
- integrity sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg==
+ version "5.6.1"
+ resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce"
+ integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ==
dependencies:
- "@octokit/endpoint" "^5.5.0"
- "@octokit/request-error" "^1.0.1"
- "@octokit/types" "^2.0.0"
- deprecation "^2.0.0"
- is-plain-object "^3.0.0"
- node-fetch "^2.3.0"
- once "^1.4.0"
- universal-user-agent "^4.0.0"
+ "@octokit/endpoint" "^6.0.1"
+ "@octokit/request-error" "^2.1.0"
+ "@octokit/types" "^6.16.1"
+ is-plain-object "^5.0.0"
+ node-fetch "^2.6.1"
+ universal-user-agent "^6.0.0"
"@octokit/rest@^16.2.0":
- version "16.38.3"
- resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.38.3.tgz#d5d200f88962392f71e048e12833ea36f4e0d192"
- integrity sha512-Ui5W4Gzv0YHe9P3KDZAuU/BkRrT88PCuuATfWBMBf4fux4nB8th8LlyVAVnHKba1s/q4umci+sNHzoFYFujPEg==
+ version "16.43.2"
+ resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b"
+ integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==
dependencies:
"@octokit/auth-token" "^2.4.0"
+ "@octokit/plugin-paginate-rest" "^1.1.1"
+ "@octokit/plugin-request-log" "^1.0.0"
+ "@octokit/plugin-rest-endpoint-methods" "2.4.0"
"@octokit/request" "^5.2.0"
"@octokit/request-error" "^1.0.2"
atob-lite "^2.0.0"
@@ -578,13 +630,20 @@
once "^1.4.0"
universal-user-agent "^4.0.0"
-"@octokit/types@^2.0.0":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.1.1.tgz#77e80d1b663c5f1f829e5377b728fa3c4fe5a97d"
- integrity sha512-89LOYH+d/vsbDX785NOfLxTW88GjNd0lWRz1DVPVsZgg9Yett5O+3MOvwo7iHgvUwbFz0mf/yPIjBkUbs4kxoQ==
+"@octokit/types@^2.0.0", "@octokit/types@^2.0.1":
+ version "2.16.2"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2"
+ integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==
dependencies:
"@types/node" ">= 8"
+"@octokit/types@^6.0.3", "@octokit/types@^6.16.1":
+ version "6.26.0"
+ resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.26.0.tgz#b8af298485d064ad9424cb41520541c1bf820346"
+ integrity sha512-RDxZBAFMtqs1ZPnbUu1e7ohPNfoNhTiep4fErY7tZs995BeHu369Vsh5woMIaFbllRWEZBfvTCS4hvDnMPiHrA==
+ dependencies:
+ "@octokit/openapi-types" "^10.0.0"
+
"@polymer/esm-amd-loader@^1.0.0":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
@@ -653,24 +712,36 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
+"@sindresorhus/is@^4.0.0":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.1.tgz#d26729db850fa327b7cacc5522252194404226f5"
+ integrity sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==
+
+"@szmarczak/http-timer@^4.0.5":
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
+ integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
+ dependencies:
+ defer-to-connect "^2.0.0"
+
"@types/babel-generator@^6.25.1":
- version "6.25.3"
- resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
- integrity sha512-pGgnuxVddKcYIc+VJkRDop7gxLhqclNKBdlsm/5Vp8d+37pQkkDK7fef8d9YYImRzw9xcojEPc18pUYnbxmjqA==
+ version "6.25.4"
+ resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.4.tgz#74eacdaa4822c4c6923e68c541144a04415ad8a1"
+ integrity sha512-Rnsen+ckop5mbl9d43bempS7i9wdTN1vytiTlmQla/YiNm6kH8kEVABVSXmp1UbnpkUV44nUCPeDQoa+Mu7ALA==
dependencies:
"@types/babel-types" "*"
"@types/babel-traverse@^6.25.2", "@types/babel-traverse@^6.25.3":
- version "6.25.5"
- resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5"
- integrity sha512-WrMbwmu+MWf8FiUMbmVOGkc7bHPzndUafn1CivMaBHthBBoo0VNIcYk1KV71UovYguhsNOwf3UF5oRmkkGOU3w==
+ version "6.25.7"
+ resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.7.tgz#bc75fce23d8394534562a36a32dec94a54d11835"
+ integrity sha512-BeQiEGLnVzypzBdsexEpZAHUx+WucOMXW6srEWDkl4SegBlaCy+iBvRO+4vz6EZ+BNQg22G4MCdDdvZxf+jW5A==
dependencies:
"@types/babel-types" "*"
"@types/babel-types@*":
- version "7.0.7"
- resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
- integrity sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==
+ version "7.0.11"
+ resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.11.tgz#263b113fa396fac4373188d73225297fb86f19a9"
+ integrity sha512-pkPtJUUY+Vwv6B1inAz55rQvivClHJxc9aVEPPmaq2cbyeMLCiDpbKpcKyX4LAwpNGi+SHBv0tHv6+0gXv0P2A==
"@types/babel-types@^6.25.1":
version "6.25.2"
@@ -678,25 +749,35 @@
integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
"@types/babylon@^6.16.2":
- version "6.16.5"
- resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
- integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
+ version "6.16.6"
+ resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.6.tgz#a1e7e01567b26a5ebad321a74d10299189d8d932"
+ integrity sha512-G4yqdVlhr6YhzLXFKy5F7HtRBU8Y23+iWy7UKthMq/OSQnL1hbsoeXESQ2LY8zEDlknipDG3nRGhUC9tkwvy/w==
dependencies:
"@types/babel-types" "*"
"@types/bluebird@*":
- version "3.5.29"
- resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.29.tgz#7cd933c902c4fc83046517a1bef973886d00bdb6"
- integrity sha512-kmVtnxTuUuhCET669irqQmPAez4KFnFVKvpleVRyfC3g+SHD1hIkFZcWLim9BVcwUBLO59o8VZE4yGCmTif8Yw==
+ version "3.5.36"
+ resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.36.tgz#00d9301d4dc35c2f6465a8aec634bb533674c652"
+ integrity sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==
"@types/body-parser@*":
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897"
- integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==
+ version "1.19.1"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c"
+ integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==
dependencies:
"@types/connect" "*"
"@types/node" "*"
+"@types/cacheable-request@^6.0.1":
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9"
+ integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==
+ dependencies:
+ "@types/http-cache-semantics" "*"
+ "@types/keyv" "*"
+ "@types/node" "*"
+ "@types/responselike" "*"
+
"@types/chai-subset@^1.3.0":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
@@ -705,9 +786,9 @@
"@types/chai" "*"
"@types/chai@*":
- version "4.2.7"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.7.tgz#1c8c25cbf6e59ffa7d6b9652c78e547d9a41692d"
- integrity sha512-luq8meHGYwvky0O7u0eQZdA7B4Wd9owUCqvbw2m3XCrCU8mplYOujMBbvyS547AxJkC+pGnd0Cm15eNxEUNU8g==
+ version "4.2.21"
+ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.21.tgz#9f35a5643129df132cf3b5c1ec64046ea1af0650"
+ integrity sha512-yd+9qKmJxm496BOV9CMNaey8TWsikaZOwMRwPHQIjcOJM9oV+fi9ZMNw3JsVnbEEbo2gRTDnGEBv8pjyn67hNg==
"@types/chalk@^0.4.30":
version "0.4.31"
@@ -722,22 +803,18 @@
chalk "*"
"@types/clean-css@*":
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d"
- integrity sha512-A1HQhQ0hkvqqByJMgg+Wiv9p9XdoYEzuwm11SVo1mX2/4PSdhjcrUlilJQoqLscIheC51t1D5g+EFWCXZ2VTQQ==
+ version "4.2.5"
+ resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.5.tgz#69ce62cc13557c90ca40460133f672dc52ceaf89"
+ integrity sha512-NEzjkGGpbs9S9fgC4abuBvTpVwE3i+Acu9BBod3PUyjDVZcNsGx61b8r2PphR61QGPnn0JHVs5ey6/I4eTrkxw==
dependencies:
"@types/node" "*"
+ source-map "^0.6.0"
"@types/clone@^0.1.29", "@types/clone@^0.1.30":
version "0.1.30"
resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
-"@types/color-name@^1.1.1":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
- integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
-
"@types/compression@^0.0.33":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
@@ -746,21 +823,21 @@
"@types/express" "*"
"@types/connect@*":
- version "3.4.33"
- resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546"
- integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==
+ version "3.4.35"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
+ integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==
dependencies:
"@types/node" "*"
"@types/content-type@^1.1.0":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
- integrity sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.5.tgz#aa02dca40864749a9e2bf0161a6216da57e3ede5"
+ integrity sha512-dgMN+syt1xb7Hk8LU6AODOfPlvz5z1CbXpPuJE5ZrX9STfBOIXF09pEB8N7a97WT9dbngt3ksDCm6GW6yMrxfQ==
"@types/cssbeautify@^0.3.1":
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
- integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.2.tgz#8a76207cd980d3e7b29b4b6dea1f4ed861285615"
+ integrity sha512-b3PXlFAcS4gvGr2pDz0NoZEBo3MMQe8Ozy6+Mvm3XIEcHS4oQstvCnnCofBZD/0tQgxSzkYbW+cD3yD4yaKTxQ==
"@types/del@^3.0.0":
version "3.0.1"
@@ -780,9 +857,9 @@
integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
"@types/estree@*":
- version "0.0.42"
- resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.42.tgz#8d0c1f480339efedb3e46070e22dd63e0430dd11"
- integrity sha512-K1DPVvnBCPxzD+G51/cxVIoc2X8uUVl1zpJeE6iKcgHMj4+tbat5Xu4TjV7v2QSDbIeAfLi2hIk+u2+s0MlpUQ==
+ version "0.0.50"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
+ integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
"@types/events@*":
version "3.0.0"
@@ -794,21 +871,23 @@
resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
-"@types/express-serve-static-core@*":
- version "4.17.2"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.2.tgz#f6f41fa35d42e79dbf6610eccbb2637e6008a0cf"
- integrity sha512-El9yMpctM6tORDAiBwZVLMcxoTMcqqRO9dVyYcn7ycLWbvR8klrDn8CAOwRfZujZtWD7yS/mshTdz43jMOejbg==
+"@types/express-serve-static-core@^4.17.18":
+ version "4.17.24"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07"
+ integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==
dependencies:
"@types/node" "*"
+ "@types/qs" "*"
"@types/range-parser" "*"
"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
- version "4.17.2"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c"
- integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA==
+ version "4.17.13"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
+ integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
dependencies:
"@types/body-parser" "*"
- "@types/express-serve-static-core" "*"
+ "@types/express-serve-static-core" "^4.17.18"
+ "@types/qs" "*"
"@types/serve-static" "*"
"@types/fast-levenshtein@0.0.1":
@@ -831,24 +910,23 @@
form-data "*"
"@types/freeport@^1.0.19":
- version "1.0.21"
- resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.21.tgz#73f6543ed67d3ca3fff97b985591598b7092066f"
- integrity sha1-c/ZUPtZ9PKP/+XuYVZFZi3CSBm8=
+ version "1.0.22"
+ resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.22.tgz#dbe627a20cb30c17c8aaaba09332e1d14cc2281f"
+ integrity sha512-UGg4s5PDPXZXkkrHarU1l6WDbULxN3g7xUEtdbNf9HQhU/JnCj1G1/xZHZmQjC0uWqN1LlB0R0xOlk3k5svgTQ==
"@types/glob-stream@*":
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
- integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.1.tgz#c792d8d1514278ff03cad5689aba4c4ab4fbc805"
+ integrity sha512-AGOUTsTdbPkRS0qDeyeS+6KypmfVpbT5j23SN8UPG63qjKXNKjXn6V9wZUr8Fin0m9l8oGYaPK8b2WUMF8xI1A==
dependencies:
"@types/glob" "*"
"@types/node" "*"
-"@types/glob@*":
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
- integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+"@types/glob@*", "@types/glob@^7.1.1":
+ version "7.1.4"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672"
+ integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
dependencies:
- "@types/events" "*"
"@types/minimatch" "*"
"@types/node" "*"
@@ -876,10 +954,15 @@
"@types/relateurl" "*"
"@types/uglify-js" "*"
+"@types/http-cache-semantics@*":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
+ integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
+
"@types/inquirer@*":
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
- integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
+ version "7.3.3"
+ resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.3.tgz#92e6676efb67fa6925c69a2ee638f67a822952ac"
+ integrity sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==
dependencies:
"@types/through" "*"
rxjs "^6.4.0"
@@ -897,10 +980,17 @@
resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff"
integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
+"@types/keyv@*":
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.2.tgz#5d97bb65526c20b6e0845f6b0d2ade4f28604ee5"
+ integrity sha512-/FvAK2p4jQOaJ6CGDHJTqZcUtbZe820qIeTg7o0Shg7drB4JHeL+V/dhSaly7NXx6u8eSee+r7coT+yuJEvDLg==
+ dependencies:
+ "@types/node" "*"
+
"@types/launchpad@^0.6.0":
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
- integrity sha1-NylhCbfyd/bmxf1+DAcGvJGPu1E=
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.1.tgz#9a5f285128598f5e0cb4a5db3e458e1b7cf07f35"
+ integrity sha512-kQ1a7PwzJelwwOIw1SABmW5OsbCRPvdjps0J84MahGsEKzN89StrPyrWCMWfwpONR3ZqSxDeblxS+8WznIBEGw==
"@types/long@^4.0.0":
version "4.0.1"
@@ -914,15 +1004,20 @@
dependencies:
"@types/node" "*"
-"@types/mime@*", "@types/mime@^2.0.0":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
- integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==
+"@types/mime@^1":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
+ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
-"@types/minimatch@*", "@types/minimatch@^3.0.1":
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
- integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+"@types/mime@^2.0.0":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
+ integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==
+
+"@types/minimatch@*", "@types/minimatch@^3.0.1", "@types/minimatch@^3.0.3":
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
+ integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/mz@0.0.29":
version "0.0.29"
@@ -940,29 +1035,29 @@
"@types/node" "*"
"@types/node@*", "@types/node@>= 8":
- version "13.5.0"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-13.5.0.tgz#4e498dbf355795a611a87ae5ef811a8660d42662"
- integrity sha512-Onhn+z72D2O2Pb2ql2xukJ55rglumsVo1H6Fmyi8mlU9SvKdBk/pUSUAiBY/d9bAOF7VVWajX3sths/+g6ZiAQ==
+ version "16.7.10"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.10.tgz#7aa732cc47341c12a16b7d562f519c2383b6d4fc"
+ integrity sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==
"@types/node@6.0.*":
version "6.0.118"
resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.118.tgz#8014a9b1dee0b72b4d7cd142563f1af21241c3a2"
integrity sha512-N33cKXGSqhOYaPiT4xUGsYlPPDwFtQM/6QxJxuMXA/7BcySW+lkn2yigWP7vfs4daiL/7NJNU6DMCqg5N4B+xQ==
-"@types/node@^10.1.0":
- version "10.17.42"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.42.tgz#90dd71b26fe4f4e2929df6b07e72ef2e9648a173"
- integrity sha512-HElxYF7C/MSkuvlaHB2c+82zhXiuO49Cq056Dol8AQuTph7oJtduo2n6J8rFa+YhJyNgQ/Lm20ZaxqD0vxU0+Q==
-
-"@types/node@^10.17.12":
- version "10.17.24"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.24.tgz#c57511e3a19c4b5e9692bb2995c40a3a52167944"
- integrity sha512-5SCfvCxV74kzR3uWgTYiGxrd69TbT1I6+cMx1A5kEly/IVveJBimtAMlXiEyVFn5DvUFewQWxOOiJhlxeQwxgA==
+"@types/node@^10.1.0", "@types/node@^10.17.12":
+ version "10.17.60"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
+ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
"@types/node@^4.0.30":
- version "4.9.4"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.4.tgz#75ef91733afaa856b01e12da6ecf48aa9d5e221f"
- integrity sha512-nKoiCZ87x6+fs26bNHjy07AQt6f46nFEitGH0P9JmWbY6tEyum6LLfLf7SIsKFh4DnBWsyUM2gYhaQAt+aA0Sw==
+ version "4.9.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.5.tgz#a3785db96b07a4b56466cc99fd624838746f2e25"
+ integrity sha512-+8fpgbXsbATKRF2ayAlYhPl2E9MPdLjrnK/79ZEpyPJ+k7dZwJm9YM8FK+l4rqL//xHk7PgQhGwz6aA2ckxbCQ==
+
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
+ integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
"@types/opn@^3.0.28":
version "3.0.28"
@@ -979,17 +1074,17 @@
"@types/parse5-sax-parser" "*"
"@types/parse5-sax-parser@*":
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/@types/parse5-sax-parser/-/parse5-sax-parser-5.0.1.tgz#f1e26e82bb09e48cb0c16ff6d1e88aea1e538fd5"
- integrity sha512-wBEwg10aACLggnb44CwzAA27M1Jrc/8TR16zA61/rKO5XZoi7JSfLjdpXbshsm7wOlM6hpfvwygh40rzM2RsQQ==
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@types/parse5-sax-parser/-/parse5-sax-parser-5.0.2.tgz#4cdca0f8bc0ce71b17e27b96e7ca9b5f79e861ff"
+ integrity sha512-EQtGoduLbdMmS4N27g6wcXdCCJ70dWYemfogWuumYg+JmzRqwYvTRAbGOYFortSHtS/qRzRCFwcP3ixy62RsdA==
dependencies:
"@types/node" "*"
"@types/parse5" "*"
"@types/parse5@*":
- version "5.0.2"
- resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.2.tgz#a877a4658f8238c8266faef300ae41c84d72ec8a"
- integrity sha512-BOl+6KDs4ItndUWUFchy3aEqGdHhw0BC4Uu+qoDonN/f0rbUnJbm71Ulj8Tt9jLFRaAxPLKvdS1bBLfx1qXR9g==
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.1.tgz#f8ae4fbcd2b9ba4ff934698e28778961f9cb22ca"
+ integrity sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==
"@types/parse5@^0.0.31":
version "0.0.31"
@@ -1006,9 +1101,9 @@
"@types/node" "*"
"@types/parse5@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-4.0.0.tgz#26dd73df171a69be517395d294c7af2ae0cd2579"
- integrity sha512-OaBwNFk6dO8gbdfWut41VYiD5Fmj3Yi24cr/oGCXFXCjT2fteSQx2l3kx/phuQvBte/F54ajN2uDQF5MRwupGw==
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-4.0.1.tgz#ec53c3f948f284be08454f622ba83765efdd06d7"
+ integrity sha512-CgJIkoNLclXUUg5cEo/SybyhxgVuKGqGcw8BPBpkKWX7wGcNfDlO2Ot+5O9u5E6k3NDg6RmJzm5w5N2prDIE8Q==
dependencies:
"@types/node" "*"
@@ -1018,21 +1113,26 @@
integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
"@types/pem@^1.8.1":
- version "1.9.5"
- resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
- integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
+ version "1.9.6"
+ resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.6.tgz#c3686832e935947fdd9d848dec3b8fe830068de7"
+ integrity sha512-IC67SxacM9fxEi/w7hf98dTun83OwUMeLMo1NS2gE0wdM9MHeg73iH/Pp9nB02OUCQ7Zb2UuKE/IpFCmQw9jxw==
dependencies:
"@types/node" "*"
+"@types/qs@*":
+ version "6.9.7"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
+ integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
+
"@types/range-parser@*":
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
- integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
+ integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
"@types/relateurl@*":
- version "0.2.28"
- resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
- integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
+ version "0.2.29"
+ resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.29.tgz#68ccecec3d4ffdafb9c577fe764f912afc050fe6"
+ integrity sha512-QSvevZ+IRww2ldtfv1QskYsqVVVwCKQf1XbwtcyyoRvLIQzfyPhj/C+3+PKzSDRdiyejaiLgnq//XTkleorpLg==
"@types/request@2.0.3":
version "2.0.3"
@@ -1070,6 +1170,13 @@
dependencies:
"@types/node" "*"
+"@types/responselike@*", "@types/responselike@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
+ integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
+ dependencies:
+ "@types/node" "*"
+
"@types/rimraf@^0.0.28":
version "0.0.28"
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
@@ -1159,9 +1266,9 @@
"@types/rx-core-binding" "*"
"@types/rx@*":
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48"
- integrity sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.2.tgz#a4061b3d72b03cf11a38d69e2022a17334c54dc0"
+ integrity sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==
dependencies:
"@types/rx-core" "*"
"@types/rx-core-binding" "*"
@@ -1182,17 +1289,17 @@
integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
"@types/serve-static@*", "@types/serve-static@^1.7.31":
- version "1.13.3"
- resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1"
- integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==
+ version "1.13.10"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9"
+ integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==
dependencies:
- "@types/express-serve-static-core" "*"
- "@types/mime" "*"
+ "@types/mime" "^1"
+ "@types/node" "*"
"@types/spdy@^3.4.1":
- version "3.4.4"
- resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.4.tgz#3282fd4ad8c4603aa49f7017dd520a08a345b2bc"
- integrity sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==
+ version "3.4.5"
+ resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.5.tgz#194dc132312ddcd31e8053789ae83a7bb32a8aaf"
+ integrity sha512-/33fIRK/aqkKNxg9BSjpzt1ucmvPremgeDywm9z2C2mOlIh5Ljjvgc3UhQHqwXsSLDLHPT9jlsnrjKQ1XiVJzA==
dependencies:
"@types/node" "*"
@@ -1211,28 +1318,26 @@
"@types/node" "*"
"@types/ua-parser-js@^0.7.31":
- version "0.7.33"
- resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.33.tgz#4a92089511574e12928a7cb6b99a01831acd1dd7"
- integrity sha512-ngUKcHnytUodUCL7C6EZ+lVXUjTMQb+9p/e1JjV5tN9TVzS98lHozWEFRPY1QcCdwFeMsmVWfZ3DPPT/udCyIw==
+ version "0.7.36"
+ resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz#9bd0b47f26b5a3151be21ba4ce9f5fa457c5f190"
+ integrity sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==
"@types/uglify-js@*":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082"
- integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ==
+ version "3.13.1"
+ resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.1.tgz#5e889e9e81e94245c75b6450600e1c5ea2878aea"
+ integrity sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==
dependencies:
source-map "^0.6.1"
"@types/update-notifier@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@types/update-notifier/-/update-notifier-1.0.3.tgz#3c7ee1921af6f16149cdcaef356baf57d7a0b806"
- integrity sha512-BLStNhP2DFF7funARwTcoD6tetRte8NK3Sc59mn7GNALCN975jOlKX3dGvsFxXr/HwQMxxCuRn9IWB3WQ7odHQ==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@types/update-notifier/-/update-notifier-1.0.4.tgz#ce73d597bd399d5df4544fe136a79c2b9fe41958"
+ integrity sha512-smyU9GTDitojg87woCcLNCdPnUfNx4LHRBWf+aWmHsAgE1kaCDhhcu84W+dFymAKL1yKDsq2JFWKkR2K6WjJfw==
"@types/uuid@^3.4.3":
- version "3.4.6"
- resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.6.tgz#d2c4c48eb85a757bf2927f75f939942d521e3016"
- integrity sha512-cCdlC/1kGEZdEglzOieLDYBxHsvEOIg7kp/2FYyVR9Pxakq+Qf/inL3RKQ+PA8gOlI/NnL+fXmQH12nwcGzsHw==
- dependencies:
- "@types/node" "*"
+ version "3.4.10"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.10.tgz#637d3c8431f112edf6728ac9bdfadfe029540f48"
+ integrity sha512-BgeaZuElf7DEYZhWYDTc/XcLZXdVgFkVSTa13BqKvbnmUrxr3TJFKofUxCtDO9UQOdhnV+HPOESdHiHKZOJV1A==
"@types/vinyl-fs@0.0.28":
version "0.0.28"
@@ -1244,18 +1349,18 @@
"@types/vinyl" "*"
"@types/vinyl-fs@^2.4.8":
- version "2.4.11"
- resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206"
- integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==
+ version "2.4.12"
+ resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.12.tgz#7b4673d9b4d5a874c8652d10f0f0265479014c8e"
+ integrity sha512-LgBpYIWuuGsihnlF+OOWWz4ovwCYlT03gd3DuLwex50cYZLmX3yrW+sFF9ndtmh7zcZpS6Ri47PrIu+fV+sbXw==
dependencies:
"@types/glob-stream" "*"
"@types/node" "*"
"@types/vinyl" "*"
"@types/vinyl@*", "@types/vinyl@^2.0.0":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a"
- integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.5.tgz#52d3b850a4ed494aaad51e96708834c500c8d5cd"
+ integrity sha512-1m6uReH8R/RuLVQGvTT/4LlWq67jZEUxp+FBHt0hYv2BT7TUwFbKI0wa7JZVEU/XtlcnX1QcTuZ36es4rGj7jg==
dependencies:
"@types/expect" "^1.20.4"
"@types/node" "*"
@@ -1285,6 +1390,14 @@
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
+JSONStream@^1.2.1, JSONStream@^1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
+ integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
+ dependencies:
+ jsonparse "^1.2.0"
+ through ">=2.2.7 <3"
+
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
@@ -1311,25 +1424,32 @@
integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
acorn@^5.5.0:
- version "5.7.3"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
- integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+ version "5.7.4"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
+ integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
acorn@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
- integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
adm-zip@~0.4.3:
- version "0.4.13"
- resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.13.tgz#597e2f8cc3672151e1307d3e95cddbc75672314a"
- integrity sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==
+ version "0.4.16"
+ resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365"
+ integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
@@ -1337,10 +1457,10 @@
dependencies:
es6-promisify "^5.0.0"
-ajv@^6.5.5:
- version "6.11.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
- integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
+ajv@^6.12.3:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
@@ -1373,10 +1493,12 @@
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
-ansi-escapes@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
- integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+ansi-escapes@^4.2.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
ansi-regex@^2.0.0:
version "2.1.1"
@@ -1388,10 +1510,10 @@
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-ansi-regex@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
- integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+ansi-regex@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+ integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
ansi-styles@^2.2.1:
version "2.2.1"
@@ -1406,11 +1528,10 @@
color-convert "^1.9.0"
ansi-styles@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
- integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
- "@types/color-name" "^1.1.1"
color-convert "^2.0.1"
ansi-styles@~1.0.0:
@@ -1501,7 +1622,7 @@
dependencies:
typical "^2.6.1"
-array-back@^3.0.1:
+array-back@^3.0.1, array-back@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
@@ -1511,6 +1632,11 @@
resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
+array-differ@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
+ integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
+
array-find-index@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
@@ -1521,13 +1647,18 @@
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
-array-union@^1.0.1:
+array-union@^1.0.1, array-union@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
dependencies:
array-uniq "^1.0.1"
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
@@ -1553,6 +1684,11 @@
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
+arrify@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
+ integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
+
asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
@@ -1575,18 +1711,23 @@
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
-async-limiter@~1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
- integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
+async@0.9.x:
+ version "0.9.2"
+ resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
+ integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
-async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.0, async@^2.6.1, async@^2.6.2, async@^2.6.3:
+async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.0, async@^2.6.2, async@^2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
dependencies:
lodash "^4.17.14"
+async@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8"
+ integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==
+
async@~0.2.9:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
@@ -1613,9 +1754,16 @@
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
- integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+
+axios@^0.21.1:
+ version "0.21.1"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
+ integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
+ dependencies:
+ follow-redirects "^1.10.0"
babel-code-frame@^6.26.0:
version "6.26.0"
@@ -1682,10 +1830,10 @@
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-dynamic-import-node@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
- integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+babel-plugin-dynamic-import-node@^2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
+ integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
dependencies:
object.assign "^4.1.0"
@@ -1902,24 +2050,24 @@
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-arraybuffer@0.1.5:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
- integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg=
+base64-arraybuffer@0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812"
+ integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=
base64-js@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
-base64-js@^1.0.2:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
- integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
+base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
base64id@2.0.0:
version "2.0.0"
@@ -1947,16 +2095,9 @@
tweetnacl "^0.14.3"
before-after-hook@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635"
- integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==
-
-better-assert@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
- integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=
- dependencies:
- callsite "1.0.0"
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e"
+ integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ==
binary-extensions@^1.0.0:
version "1.13.1"
@@ -1964,9 +2105,9 @@
integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
binaryextensions@^2.1.2:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.2.0.tgz#e7c6ba82d4f5f5758c26078fe8eea28881233311"
- integrity sha512-bHhs98rj/7i/RZpCSJ3uk55pLXOItjIrh2sRQZSM6OoktScX+LxJzvlU+FELp9j3TdcddTmmYArLSGptCTwjuw==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22"
+ integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==
bindings@^1.5.0:
version "1.5.0"
@@ -1976,27 +2117,21 @@
file-uri-to-path "1.0.0"
bl@^1.0.0:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
- integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
+ integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==
dependencies:
readable-stream "^2.3.5"
safe-buffer "^5.1.1"
-bl@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493"
- integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==
+bl@^4.0.3:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
dependencies:
- readable-stream "^2.3.5"
- safe-buffer "^5.1.1"
-
-bl@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
- integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
- dependencies:
- readable-stream "^3.0.1"
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
blob@0.0.5:
version "0.0.5"
@@ -2020,25 +2155,28 @@
type-is "~1.6.17"
bower-config@^1.4.0, bower-config@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.1.tgz#85fd9df367c2b8dbbd0caa4c5f2bad40cd84c2cc"
- integrity sha1-hf2d82fCuNu9DKpMXyutQM2Ewsw=
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.3.tgz#3454fecdc5f08e7aa9cc6d556e492be0669689ae"
+ integrity sha512-MVyyUk3d1S7d2cl6YISViwJBc2VXCkxF5AUFykvN0PQj5FsUiMNSgAYTso18oRFfyZ6XEtjrgg9MAaufHbOwNw==
dependencies:
graceful-fs "^4.1.3"
+ minimist "^0.2.1"
mout "^1.0.0"
- optimist "^0.6.1"
osenv "^0.1.3"
untildify "^2.1.0"
+ wordwrap "^0.0.3"
bower-json@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.1.tgz#96c14723241ae6466a9c52e16caa32623a883843"
- integrity sha1-lsFHIyQa5kZqnFLhbKoyYjqIOEM=
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.4.tgz#9c3b375870dcd9581350c1f403f6383dbf6a18b1"
+ integrity sha512-mMKghvq9ivbuzSsY5nrOLnDtZIJMUCpysqbGaGW3mj88JAcuSi8ZAzIt34vNZjohy0aR9VXLwgPTZGnBX2Vpjg==
dependencies:
- deep-extend "^0.4.0"
- ext-name "^3.0.0"
+ deep-extend "^0.5.1"
+ ends-with "^0.2.0"
+ ext-list "^2.0.0"
graceful-fs "^4.1.3"
intersect "^1.0.1"
+ sort-keys-length "^1.0.0"
bower-logger@^0.2.2:
version "0.2.2"
@@ -2046,9 +2184,9 @@
integrity sha1-Ob4H6Xmy/I4DqUY0IF7ZQiNz04E=
bower@^1.8.8:
- version "1.8.8"
- resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.8.tgz#82544be34a33aeae7efb8bdf9905247b2cffa985"
- integrity sha512-1SrJnXnkP9soITHptSO+ahx3QKp3cVzn8poI6ujqc5SeOkg5iqM1pK9H+DSc2OQ8SnO0jC/NG4Ur/UIwy7574A==
+ version "1.8.12"
+ resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.12.tgz#44cfca2a5e04b8d9a066621e24c8b179d8ac321e"
+ integrity sha512-u1xy9SrwwoPlgjuHNjhV+YUPVdqyBj2ALBxuzeIUKXaPI2i2xypGgxqXkuHcITGdi5yBj5JuXgyMvgiWiS1S3Q==
boxen@^0.6.0:
version "0.6.0"
@@ -2126,10 +2264,21 @@
dependencies:
pako "~0.2.0"
+browserslist@^4.16.6:
+ version "4.16.8"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.8.tgz#cb868b0b554f137ba6e33de0ecff2eda403c4fb0"
+ integrity sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==
+ dependencies:
+ caniuse-lite "^1.0.30001251"
+ colorette "^1.3.0"
+ electron-to-chromium "^1.3.811"
+ escalade "^3.1.1"
+ node-releases "^1.1.75"
+
browserstack@^1.2.0:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.5.3.tgz#93ab48799a12ef99dbd074dd595410ddb196a7ac"
- integrity sha512-AO+mECXsW4QcqC9bxwM29O7qWa7bJT94uBFzeb5brylIQwawuEziwq20dPYbins95GlWzOawgyDNdjYAo32EKg==
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3"
+ integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==
dependencies:
https-proxy-agent "^2.2.1"
@@ -2162,22 +2311,22 @@
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-buffer@^5.1.0:
- version "5.4.3"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115"
- integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==
+buffer@^5.1.0, buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
dependencies:
- base64-js "^1.0.2"
- ieee754 "^1.1.4"
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
builtin-modules@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484"
- integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
+ integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
busboy@^0.2.11:
version "0.2.14"
@@ -2212,16 +2361,37 @@
union-value "^1.0.0"
unset-value "^1.0.0"
+cacheable-lookup@^5.0.3:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
+ integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+
+cacheable-request@^7.0.1:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
+ integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==
+ dependencies:
+ clone-response "^1.0.2"
+ get-stream "^5.1.0"
+ http-cache-semantics "^4.0.0"
+ keyv "^4.0.0"
+ lowercase-keys "^2.0.0"
+ normalize-url "^6.0.1"
+ responselike "^2.0.0"
+
+call-bind@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
+ integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
+ dependencies:
+ function-bind "^1.1.1"
+ get-intrinsic "^1.0.2"
+
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-callsite@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
- integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
-
camel-case@3.0.x:
version "3.0.0"
resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
@@ -2255,6 +2425,11 @@
dependencies:
"@types/node" "^4.0.30"
+caniuse-lite@^1.0.30001251:
+ version "1.0.30001252"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001252.tgz#cb16e4e3dafe948fc4a9bb3307aea054b912019a"
+ integrity sha512-I56jhWDGMtdILQORdusxBOH+Nl/KgQSdDmpJezYddnAkVOmnoU8zwjTV9xAjMIYxr0iPreEAVylCGcmHCjfaOw==
+
capture-stack-trace@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
@@ -2265,10 +2440,10 @@
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-chalk@*:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+chalk@*, chalk@^4.1.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
@@ -2307,7 +2482,7 @@
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-charenc@~0.0.1:
+charenc@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
@@ -2329,9 +2504,9 @@
fsevents "^1.0.0"
chownr@^1.0.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142"
- integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
ci-info@^1.5.0:
version "1.6.0"
@@ -2349,9 +2524,9 @@
static-extend "^0.1.1"
clean-css@4.2.x:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.2.tgz#8519abda724b3e759bc79d196369906925d81a3f"
- integrity sha512-yKycArwReQXbOD/3pmsPmt6p7oUBww8MisDabL2pCUWkbVONvCJoBdCjgY4ZVQmKX5juz/JB9oDcP6XzGUpjwQ==
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
+ integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
dependencies:
source-map "~0.6.0"
@@ -2372,30 +2547,51 @@
dependencies:
restore-cursor "^1.0.1"
-cli-cursor@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
- integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
dependencies:
- restore-cursor "^2.0.0"
+ restore-cursor "^3.1.0"
cli-table@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23"
- integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM=
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.6.tgz#e9d6aa859c7fe636981fd3787378c2a20bce92fc"
+ integrity sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==
dependencies:
colors "1.0.3"
cli-width@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
- integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
+ integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
+
+cli-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clone-buffer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
+clone-deep@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
+ integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
+ dependencies:
+ is-plain-object "^2.0.4"
+ kind-of "^6.0.2"
+ shallow-clone "^3.0.0"
+
+clone-response@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
+ integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
+ dependencies:
+ mimic-response "^1.0.0"
+
clone-stats@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
@@ -2463,9 +2659,9 @@
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.5.2:
- version "1.5.3"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc"
- integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312"
+ integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
@@ -2478,10 +2674,10 @@
color-convert "^1.9.1"
color-string "^1.5.2"
-colornames@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/colornames/-/colornames-1.1.1.tgz#f8889030685c7c4ff9e2a559f5077eb76a816f96"
- integrity sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=
+colorette@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af"
+ integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==
colors@1.0.3:
version "1.0.3"
@@ -2519,11 +2715,11 @@
typical "^2.6.0"
command-line-args@^5.0.2:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
- integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.0.tgz#087b02748272169741f1fd7c785b295df079b9be"
+ integrity sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==
dependencies:
- array-back "^3.0.1"
+ array-back "^3.1.0"
find-replace "^3.0.0"
lodash.camelcase "^4.3.0"
typical "^4.0.0"
@@ -2561,7 +2757,7 @@
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
-commander@^2.19.0, commander@^2.20.0:
+commander@^2.20.0, commander@^2.20.3:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
@@ -2586,7 +2782,7 @@
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
-component-emitter@^1.2.1:
+component-emitter@^1.2.1, component-emitter@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
@@ -2657,11 +2853,11 @@
xdg-basedir "^2.0.0"
configstore@^3.0.0:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
- integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.5.tgz#e9af331fadc14dabd544d3e7e76dc446a09a530f"
+ integrity sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==
dependencies:
- dot-prop "^4.1.0"
+ dot-prop "^4.2.1"
graceful-fs "^4.1.2"
make-dir "^1.0.0"
unique-string "^1.0.0"
@@ -2681,9 +2877,9 @@
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
convert-source-map@^1.1.1, convert-source-map@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
- integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
+ integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
dependencies:
safe-buffer "~5.1.1"
@@ -2692,31 +2888,36 @@
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-cookie@0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
- integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
-
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookie@~0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
+ integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
+
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
core-js@^2.4.0, core-js@^2.4.1:
- version "2.6.11"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
- integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
+ version "2.6.12"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
+ integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
-core-util-is@1.0.2, core-util-is@~1.0.0:
+core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
cors@^2.8.4:
version "2.8.5"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
@@ -2776,7 +2977,16 @@
shebang-command "^1.2.0"
which "^1.2.9"
-crypt@~0.0.1:
+cross-spawn@^7.0.0, cross-spawn@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+crypt@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
@@ -2814,7 +3024,7 @@
dependencies:
array-find-index "^1.0.1"
-dargs@^6.0.0:
+dargs@^6.0.0, dargs@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/dargs/-/dargs-6.1.0.tgz#1f3b9b56393ecf8caa7cbfd6c31496ffcfb9b272"
integrity sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==
@@ -2838,17 +3048,17 @@
dependencies:
ms "2.0.0"
-debug@^3.0.0, debug@^3.1.0:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
- integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
+ integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
dependencies:
- ms "^2.1.1"
+ ms "2.1.2"
-debug@^4.1.0, debug@^4.1.1, debug@~4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+debug@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
@@ -2859,6 +3069,13 @@
dependencies:
ms "2.0.0"
+debug@~4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+ integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+ dependencies:
+ ms "^2.1.1"
+
decamelize@^1.1.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -2876,17 +3093,34 @@
dependencies:
mimic-response "^1.0.0"
-deep-extend@^0.4.0, deep-extend@~0.4.1:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
- integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
+decompress-response@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+ integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+ dependencies:
+ mimic-response "^3.1.0"
+
+deep-extend@^0.5.1:
+ version "0.5.1"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f"
+ integrity sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==
deep-extend@^0.6.0, deep-extend@~0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-define-properties@^1.1.2:
+deep-extend@~0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
+ integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=
+
+defer-to-connect@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
+ integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
+
+define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -2937,7 +3171,7 @@
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-deprecation@^2.0.0:
+deprecation@^2.0.0, deprecation@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
@@ -2972,18 +3206,9 @@
repeating "^2.0.0"
detect-node@^2.0.3:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
- integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
-
-diagnostics@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.1.tgz#cab6ac33df70c9d9a727490ae43ac995a769b22a"
- integrity sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==
- dependencies:
- colorspace "1.1.x"
- enabled "1.0.x"
- kuler "1.0.x"
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+ integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
dicer@0.2.5:
version "0.2.5"
@@ -3003,6 +3228,11 @@
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
+diff@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+ integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
dir-glob@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
@@ -3011,6 +3241,13 @@
arrify "^1.0.1"
path-type "^3.0.0"
+dir-glob@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
+ integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==
+ dependencies:
+ path-type "^3.0.0"
+
doctrine@^2.0.2:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -3052,13 +3289,22 @@
dependencies:
is-obj "^1.0.0"
-dot-prop@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
- integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
+dot-prop@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4"
+ integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==
dependencies:
is-obj "^1.0.0"
+download-stats@^0.3.4:
+ version "0.3.4"
+ resolved "https://registry.yarnpkg.com/download-stats/-/download-stats-0.3.4.tgz#67ea0c32f14acd9f639da704eef509684ba2dae7"
+ integrity sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==
+ dependencies:
+ JSONStream "^1.2.1"
+ lazy-cache "^2.0.1"
+ moment "^2.15.1"
+
duplexer2@^0.1.2, duplexer2@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
@@ -3090,9 +3336,9 @@
safer-buffer "^2.1.0"
editions@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.0.tgz#47f2d5309340bce93ab5eb6ad755b9e90ff825e4"
- integrity sha512-jeXYwHPKbitU1l14dWlsl5Nm+b1Hsm7VX73BsrQ4RVwEcAQQIPFHTZAbVtuIGxZBrpdT2FXd8lbtrNBrzZxIsA==
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698"
+ integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==
dependencies:
errlop "^2.0.0"
semver "^6.3.0"
@@ -3102,22 +3348,37 @@
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-ejs@^2.5.9:
+ejs@^2.5.9, ejs@^2.6.1:
version "2.7.4"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
+ejs@^3.1.5:
+ version "3.1.6"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a"
+ integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==
+ dependencies:
+ jake "^10.6.1"
+
+electron-to-chromium@^1.3.811:
+ version "1.3.826"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.826.tgz#dbe356b1546b39d83bcd47e675a9c5f61dadaed2"
+ integrity sha512-bpLc4QU4B8PYmdO4MSu2ZBTMD8lAaEXRS43C09lB31BvYwuk9UxgBRXbY5OJBw7VuMGcg2MZG5FyTaP9u4PQnw==
+
emitter-component@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
-enabled@1.0.x:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
- integrity sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=
- dependencies:
- env-variable "0.0.x"
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
encodeurl@~1.0.2:
version "1.0.2"
@@ -3136,55 +3397,50 @@
resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a"
integrity sha1-L52pjVelDP2kVxzkM5AAUA9Oa4o=
-engine.io-client@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.0.tgz#82a642b42862a9b3f7a188f41776b2deab643700"
- integrity sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==
+engine.io-client@~3.5.0:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.5.2.tgz#0ef473621294004e9ceebe73cef0af9e36f2f5fa"
+ integrity sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA==
dependencies:
- component-emitter "1.2.1"
+ component-emitter "~1.3.0"
component-inherit "0.0.3"
- debug "~4.1.0"
+ debug "~3.1.0"
engine.io-parser "~2.2.0"
has-cors "1.1.0"
indexof "0.0.1"
- parseqs "0.0.5"
- parseuri "0.0.5"
- ws "~6.1.0"
- xmlhttprequest-ssl "~1.5.4"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
+ ws "~7.4.2"
+ xmlhttprequest-ssl "~1.6.2"
yeast "0.1.2"
engine.io-parser@~2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed"
- integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
+ integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==
dependencies:
after "0.8.2"
arraybuffer.slice "~0.0.7"
- base64-arraybuffer "0.1.5"
+ base64-arraybuffer "0.1.4"
blob "0.0.5"
has-binary2 "~1.0.2"
-engine.io@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.0.tgz#3a962cc4535928c252759a00f98519cb46c53ff3"
- integrity sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==
+engine.io@~3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
+ integrity sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==
dependencies:
accepts "~1.3.4"
base64id "2.0.0"
- cookie "0.3.1"
+ cookie "~0.4.1"
debug "~4.1.0"
engine.io-parser "~2.2.0"
- ws "^7.1.2"
-
-env-variable@0.0.x:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.5.tgz#913dd830bef11e96a039c038d4130604eba37f88"
- integrity sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==
+ ws "~7.4.2"
errlop@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.0.0.tgz#52b97d35da1b0795e2647b5d2d3a46d17776f55a"
- integrity sha512-z00WIrQhtOMUnjdTG0O4f6hMG64EVccVDBy2WwgjcF8S4UB1exGYuc2OFwmdQmsJwLQVEIHWHPCz/omXXgAZHw==
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b"
+ integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==
error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
@@ -3213,9 +3469,14 @@
es6-promise "^4.0.3"
es6-promisify@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.2.tgz#525c23725b8510f5f1f2feb5a1fbad93a93e29b4"
- integrity sha512-eO6vFm0JvqGzjWIQA6QVKjxpmELfhWbDUWHm1rPfIbn55mhKPiAa5xpLmQWJrNa629ZIeQ8ZvMAi13kvrjK6Mg==
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
+ integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==
+
+escalade@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
+ integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-html@^1.0.3, escape-html@~1.0.3:
version "1.0.3"
@@ -3251,9 +3512,9 @@
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter3@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb"
- integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
execa@^0.7.0:
version "0.7.0"
@@ -3281,6 +3542,21 @@
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
+ integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
+ dependencies:
+ cross-spawn "^7.0.0"
+ get-stream "^5.0.0"
+ human-signals "^1.1.1"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.0"
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+ strip-final-newline "^2.0.0"
+
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
@@ -3370,16 +3646,6 @@
dependencies:
mime-db "^1.28.0"
-ext-name@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-3.0.0.tgz#07e4418737cb1f513c32c6ea48d8b8c8e0471abb"
- integrity sha1-B+RBhzfLH1E8MsbqSNi4yOBHGrs=
- dependencies:
- ends-with "^0.2.0"
- ext-list "^2.0.0"
- meow "^3.1.0"
- sort-keys-length "^1.0.0"
-
extend-shallow@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -3450,11 +3716,11 @@
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
fast-deep-equal@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
- integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^2.0.2:
+fast-glob@^2.0.2, fast-glob@^2.2.6:
version "2.2.7"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
@@ -3477,9 +3743,9 @@
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fast-safe-stringify@^2.0.4:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
- integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f"
+ integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==
fd-slicer@~1.1.0:
version "1.1.0"
@@ -3500,6 +3766,11 @@
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+fecha@^4.2.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce"
+ integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==
+
figures@^1.3.5:
version "1.7.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
@@ -3508,10 +3779,10 @@
escape-string-regexp "^1.0.5"
object-assign "^4.1.0"
-figures@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
- integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+figures@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
dependencies:
escape-string-regexp "^1.0.5"
@@ -3520,6 +3791,13 @@
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
+filelist@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b"
+ integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==
+ dependencies:
+ minimatch "^3.0.4"
+
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -3633,12 +3911,15 @@
dependencies:
readable-stream "^2.0.2"
-follow-redirects@^1.0.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.10.0.tgz#01f5263aee921c6a54fb91667f08f4155ce169eb"
- integrity sha512-4eyLK6s6lH32nOvLLwlIOnr9zrL8Sm+OvW4pVTJNoXeGzYIkHVf+pADQi+OJ0E67hiuSLezPVPyBcIZO50TmmQ==
- dependencies:
- debug "^3.0.0"
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
+
+follow-redirects@^1.0.0, follow-redirects@^1.10.0:
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.2.tgz#cecb825047c00f5e66b142f90fed4f515dec789b"
+ integrity sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==
for-in@^1.0.1, for-in@^1.0.2:
version "1.0.2"
@@ -3663,9 +3944,9 @@
integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
form-data@*:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
- integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
@@ -3687,10 +3968,10 @@
dependencies:
samsam "1.x"
-forwarded@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
- integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
fragment-cache@^0.2.1:
version "0.2.1"
@@ -3725,27 +4006,36 @@
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
fsevents@^1.0.0:
- version "1.2.11"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3"
- integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
+ integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
dependencies:
bindings "^1.5.0"
nan "^2.12.1"
-fsevents@~2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
- integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
+fsevents@~2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
+ integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-gensync@^1.0.0-beta.1:
- version "1.0.0-beta.1"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
- integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-intrinsic@^1.0.2:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
+ integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
+ dependencies:
+ function-bind "^1.1.1"
+ has "^1.0.3"
+ has-symbols "^1.0.1"
get-stdin@^4.0.1:
version "4.0.1"
@@ -3764,6 +4054,13 @@
dependencies:
pump "^3.0.0"
+get-stream@^5.0.0, get-stream@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+ dependencies:
+ pump "^3.0.0"
+
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -3776,6 +4073,14 @@
dependencies:
assert-plus "^1.0.0"
+gh-got@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-5.0.0.tgz#ee95be37106fd8748a96f8d1db4baea89e1bfa8a"
+ integrity sha1-7pW+NxBv2HSKlvjR20uuqJ4b+oo=
+ dependencies:
+ got "^6.2.0"
+ is-plain-obj "^1.1.0"
+
gh-got@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0"
@@ -3784,6 +4089,13 @@
got "^7.0.0"
is-plain-obj "^1.1.0"
+github-username@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/github-username/-/github-username-3.0.0.tgz#0a772219b3130743429f2456d0bdd3db55dce7b1"
+ integrity sha1-CnciGbMTB0NCnyRW0L3T21Xc57E=
+ dependencies:
+ gh-got "^5.0.0"
+
github-username@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417"
@@ -3856,9 +4168,9 @@
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -3958,6 +4270,37 @@
pify "^3.0.0"
slash "^1.0.0"
+globby@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
+ integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
+ dependencies:
+ "@types/glob" "^7.1.1"
+ array-union "^1.0.2"
+ dir-glob "^2.2.2"
+ fast-glob "^2.2.6"
+ glob "^7.1.3"
+ ignore "^4.0.3"
+ pify "^4.0.1"
+ slash "^2.0.0"
+
+got@^11.8.2:
+ version "11.8.2"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
+ integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==
+ dependencies:
+ "@sindresorhus/is" "^4.0.0"
+ "@szmarczak/http-timer" "^4.0.5"
+ "@types/cacheable-request" "^6.0.1"
+ "@types/responselike" "^1.0.0"
+ cacheable-lookup "^5.0.3"
+ cacheable-request "^7.0.1"
+ decompress-response "^6.0.0"
+ http2-wrapper "^1.0.0-beta.5.2"
+ lowercase-keys "^2.0.0"
+ p-cancelable "^2.0.0"
+ responselike "^2.0.0"
+
got@^5.0.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
@@ -3979,7 +4322,7 @@
unzip-response "^1.0.2"
url-parse-lax "^1.0.0"
-got@^6.7.1:
+got@^6.2.0, got@^6.7.1:
version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
@@ -4017,17 +4360,24 @@
url-to-options "^1.0.1"
graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.0:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
- integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
+ integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
-grouped-queue@^0.3.0, grouped-queue@^0.3.3:
+grouped-queue@^0.3.0:
version "0.3.3"
resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c"
integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=
dependencies:
lodash "^4.17.2"
+grouped-queue@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-1.1.0.tgz#63e3f9ca90af952269d1d40879e41221eacc74cb"
+ integrity sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==
+ dependencies:
+ lodash "^4.17.15"
+
gulp-if@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
@@ -4056,9 +4406,9 @@
vinyl "^1.0.0"
gunzip-maybe@^1.3.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.1.tgz#39c72ed89d1b49ba708e18776500488902a52027"
- integrity sha512-qtutIKMthNJJgeHQS7kZ9FqDq59/Wn0G2HYCRNjpup7yKfVI6/eqwpmroyZGFoCYaG+sW6psNVb4zoLADHpp2g==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac"
+ integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==
dependencies:
browserify-zlib "^0.1.4"
is-deflate "^1.0.0"
@@ -4077,12 +4427,12 @@
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-har-validator@~5.1.0:
- version "5.1.3"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
- integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+har-validator@~5.1.0, har-validator@~5.1.3:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
dependencies:
- ajv "^6.5.5"
+ ajv "^6.12.3"
har-schema "^2.0.0"
has-ansi@^2.0.0:
@@ -4124,10 +4474,10 @@
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
-has-symbols@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
- integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
+has-symbols@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
+ integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has-to-string-tag-x@^1.2.0:
version "1.4.1"
@@ -4167,6 +4517,13 @@
is-number "^3.0.0"
kind-of "^4.0.0"
+has@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+ integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+ dependencies:
+ function-bind "^1.1.1"
+
he@1.2.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -4180,9 +4537,9 @@
parse-passwd "^1.0.0"
hosted-git-info@^2.1.4:
- version "2.8.5"
- resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
- integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
hpack.js@^2.1.6:
version "2.1.6"
@@ -4207,6 +4564,11 @@
relateurl "0.2.x"
uglify-js "3.4.x"
+http-cache-semantics@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
+ integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
+
http-deceiver@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@@ -4255,9 +4617,9 @@
micromatch "^2.3.11"
http-proxy@^1.16.2:
- version "1.18.0"
- resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a"
- integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
@@ -4272,6 +4634,14 @@
jsprim "^1.2.2"
sshpk "^1.7.0"
+http2-wrapper@^1.0.0-beta.5.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
+ integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
+ dependencies:
+ quick-lru "^5.1.1"
+ resolve-alpn "^1.0.0"
+
https-proxy-agent@^2.2.1:
version "2.2.4"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
@@ -4280,13 +4650,18 @@
agent-base "^4.3.0"
debug "^3.1.0"
-https-proxy-agent@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz#b8c286433e87602311b01c8ea34413d856a4af81"
- integrity sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==
+https-proxy-agent@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
+ integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
dependencies:
- agent-base "^4.3.0"
- debug "^3.1.0"
+ agent-base "6"
+ debug "4"
+
+human-signals@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
+ integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
@@ -4295,16 +4670,21 @@
dependencies:
safer-buffer ">= 2.1.2 < 3"
-ieee754@^1.1.4:
- version "1.1.13"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
- integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+ieee754@^1.1.13:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^3.3.5:
version "3.3.10"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
+ignore@^4.0.3:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
@@ -4340,7 +4720,7 @@
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -4351,9 +4731,9 @@
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@^1.3.4, ini@~1.3.0:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
- integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inquirer@^1.0.2:
version "1.2.3"
@@ -4375,29 +4755,29 @@
strip-ansi "^3.0.0"
through "^2.3.6"
-inquirer@^6.0.0:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca"
- integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==
+inquirer@^7.1.0:
+ version "7.3.3"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
+ integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
- ansi-escapes "^3.2.0"
- chalk "^2.4.2"
- cli-cursor "^2.1.0"
- cli-width "^2.0.0"
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
external-editor "^3.0.3"
- figures "^2.0.0"
- lodash "^4.17.12"
- mute-stream "0.0.7"
- run-async "^2.2.0"
- rxjs "^6.4.0"
- string-width "^2.1.0"
- strip-ansi "^5.1.0"
+ figures "^3.0.0"
+ lodash "^4.17.19"
+ mute-stream "0.0.8"
+ run-async "^2.4.0"
+ rxjs "^6.6.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
through "^2.3.6"
interpret@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
- integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
intersect@^1.0.1:
version "1.0.1"
@@ -4411,10 +4791,10 @@
dependencies:
loose-envify "^1.0.0"
-ipaddr.js@1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
- integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
is-accessor-descriptor@^0.1.6:
version "0.1.6"
@@ -4447,7 +4827,7 @@
dependencies:
binary-extensions "^1.0.0"
-is-buffer@^1.1.5, is-buffer@~1.1.1:
+is-buffer@^1.1.5, is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
@@ -4459,6 +4839,13 @@
dependencies:
ci-info "^1.5.0"
+is-core-module@^2.2.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
+ integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
+ dependencies:
+ has "^1.0.3"
+
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -4531,11 +4918,9 @@
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-finite@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
- integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
- dependencies:
- number-is-nan "^1.0.0"
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
+ integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
is-fullwidth-code-point@^1.0.0:
version "1.0.0"
@@ -4549,6 +4934,11 @@
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
is-glob@^2.0.0, is-glob@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
@@ -4618,9 +5008,9 @@
integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
is-object@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470"
- integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA=
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf"
+ integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==
is-path-cwd@^1.0.0:
version "1.0.0"
@@ -4653,12 +5043,10 @@
dependencies:
isobject "^3.0.1"
-is-plain-object@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928"
- integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==
- dependencies:
- isobject "^4.0.0"
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
is-posix-bracket@^0.1.0:
version "0.1.1"
@@ -4666,20 +5054,15 @@
integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
is-potential-custom-element-name@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397"
- integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
+ integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
-is-promise@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
- integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
-
is-redirect@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
@@ -4702,12 +5085,17 @@
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-is-utf8@^0.2.0:
+is-utf8@^0.2.0, is-utf8@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
@@ -4749,6 +5137,11 @@
dependencies:
buffer-alloc "^1.2.0"
+isbinaryfile@^4.0.0:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.8.tgz#5d34b94865bd4946633ecc78a026fc76c5b11fcf"
+ integrity sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==
+
isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -4766,17 +5159,12 @@
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-isobject@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
- integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
-
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-istextorbinary@^2.2.1:
+istextorbinary@^2.2.1, istextorbinary@^2.5.1:
version "2.6.0"
resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab"
integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==
@@ -4793,6 +5181,16 @@
has-to-string-tag-x "^1.2.0"
is-object "^1.0.1"
+jake@^10.6.1:
+ version "10.8.2"
+ resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b"
+ integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==
+ dependencies:
+ async "0.9.x"
+ chalk "^2.4.2"
+ filelist "^1.0.1"
+ minimatch "^3.0.4"
+
jest-worker@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5"
@@ -4831,11 +5229,21 @@
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+json-parse-even-better-errors@^2.3.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
json-schema-traverse@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
@@ -4856,17 +5264,22 @@
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-json5@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
- integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
+json5@^2.1.2:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
+ integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
- minimist "^1.2.0"
+ minimist "^1.2.5"
+
+jsonparse@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+ integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
jsonschema@^1.1.0, jsonschema@^1.1.1:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.2.5.tgz#bab69d97fa28946aec0a56a9cc266d23fe80ae61"
- integrity sha512-kVTF+08x25PQ0CjuVc0gRM9EUPb0Fe9Ln/utFOgcdxEIOHuU7ooBk/UPTd7t1M91pP35m0MU1T8M5P7vP1bRRw==
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2"
+ integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==
jsprim@^1.2.2:
version "1.4.1"
@@ -4878,6 +5291,13 @@
json-schema "0.2.3"
verror "1.10.0"
+keyv@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
+ integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
+ dependencies:
+ json-buffer "3.0.1"
+
kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
@@ -4902,12 +5322,10 @@
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-kuler@1.0.x:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/kuler/-/kuler-1.0.1.tgz#ef7c784f36c9fb6e16dd3150d152677b2b0228a6"
- integrity sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==
- dependencies:
- colornames "^1.1.1"
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
latest-version@^2.0.0:
version "2.0.0"
@@ -4937,6 +5355,13 @@
rimraf "^3.0.0"
underscore "^1.8.3"
+lazy-cache@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
+ integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
+ dependencies:
+ set-getter "^0.1.0"
+
lazy-req@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
@@ -4949,6 +5374,11 @@
dependencies:
readable-stream "^2.0.5"
+lines-and-columns@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+ integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -5018,6 +5448,16 @@
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
+lodash.mapvalues@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
+ integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
lodash.padend@^4.6.1:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
@@ -5058,15 +5498,10 @@
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-lodash@^3.0.0, lodash@^3.10.1:
- version "3.10.1"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
- integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-
-lodash@^4.0.0, lodash@^4.11.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0:
- version "4.17.15"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
- integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
+lodash@4.17.21, lodash@^3.0.0, lodash@^3.10.1, lodash@^4.0.0, lodash@^4.11.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.3.0:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^1.0.0, log-symbols@^1.0.1:
version "1.0.2"
@@ -5093,14 +5528,14 @@
ms "^2.1.1"
triple-beam "^1.2.0"
-logform@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/logform/-/logform-2.1.2.tgz#957155ebeb67a13164069825ce67ddb5bb2dd360"
- integrity sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==
+logform@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2"
+ integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==
dependencies:
colors "^1.2.1"
fast-safe-stringify "^2.0.4"
- fecha "^2.3.3"
+ fecha "^4.2.0"
ms "^2.1.1"
triple-beam "^1.3.0"
@@ -5139,6 +5574,11 @@
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
+lowercase-keys@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+ integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
lru-cache@^4.0.1, lru-cache@^4.0.2:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -5147,10 +5587,17 @@
pseudomap "^1.0.2"
yallist "^2.1.2"
+lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
macos-release@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f"
- integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2"
+ integrity sha512-EIgv+QZ9r+814gjJj0Bt5vSLJLzswGmSUbUpbi9AIr/fsN2IWFBl2NucV9PAiek+U1STK468tEkxmVYUtuAN3g==
magic-string@^0.22.4:
version "0.22.5"
@@ -5166,6 +5613,13 @@
dependencies:
pify "^3.0.0"
+make-dir@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
@@ -5196,13 +5650,13 @@
integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
md5@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
- integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
+ integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
- charenc "~0.0.1"
- crypt "~0.0.1"
- is-buffer "~1.1.1"
+ charenc "0.0.2"
+ crypt "0.0.2"
+ is-buffer "~1.1.6"
media-typer@0.3.0:
version "0.3.0"
@@ -5226,16 +5680,50 @@
through2 "^2.0.0"
vinyl "^2.0.1"
-mem-fs@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.1.3.tgz#b8ae8d2e3fcb6f5d3f9165c12d4551a065d989cc"
- integrity sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=
+mem-fs-editor@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-6.0.0.tgz#d63607cf0a52fe6963fc376c6a7aa52db3edabab"
+ integrity sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==
dependencies:
- through2 "^2.0.0"
- vinyl "^1.1.0"
- vinyl-file "^2.0.0"
+ commondir "^1.0.1"
+ deep-extend "^0.6.0"
+ ejs "^2.6.1"
+ glob "^7.1.4"
+ globby "^9.2.0"
+ isbinaryfile "^4.0.0"
+ mkdirp "^0.5.0"
+ multimatch "^4.0.0"
+ rimraf "^2.6.3"
+ through2 "^3.0.1"
+ vinyl "^2.2.0"
-meow@^3.1.0, meow@^3.7.0:
+mem-fs-editor@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-7.1.0.tgz#2a16f143228df87bf918874556723a7ee73bfe88"
+ integrity sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==
+ dependencies:
+ commondir "^1.0.1"
+ deep-extend "^0.6.0"
+ ejs "^3.1.5"
+ glob "^7.1.4"
+ globby "^9.2.0"
+ isbinaryfile "^4.0.0"
+ mkdirp "^1.0.0"
+ multimatch "^4.0.0"
+ rimraf "^3.0.0"
+ through2 "^3.0.2"
+ vinyl "^2.2.1"
+
+mem-fs@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.2.0.tgz#5f29b2d02a5875cd14cd836c388385892d556cde"
+ integrity sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==
+ dependencies:
+ through2 "^3.0.0"
+ vinyl "^2.0.1"
+ vinyl-file "^3.0.0"
+
+meow@^3.7.0:
version "3.7.0"
resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
@@ -5269,9 +5757,9 @@
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
merge2@^1.2.3:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
- integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
methods@~1.1.2:
version "1.1.2"
@@ -5316,17 +5804,17 @@
snapdragon "^0.8.1"
to-regex "^3.0.2"
-mime-db@1.43.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
- version "1.43.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
- integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
+mime-db@1.49.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
+ version "1.49.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
+ integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
- version "2.1.26"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
- integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
+ version "2.1.32"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
+ integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==
dependencies:
- mime-db "1.43.0"
+ mime-db "1.49.0"
mime@1.4.1:
version "1.4.1"
@@ -5339,20 +5827,25 @@
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
mime@^2.3.1:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
- integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
+ integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
-mimic-fn@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
- integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+mimic-response@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+ integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
minimalistic-assert@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@@ -5372,20 +5865,15 @@
dependencies:
brace-expansion "^1.1.7"
-minimist@0.0.8:
- version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
- integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+minimist@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.1.tgz#827ba4e7593464e7c221e8c5bed930904ee2c455"
+ integrity sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==
-minimist@^1.1.3, minimist@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
- integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
-
-minimist@~0.0.1:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
- integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=
+minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
+ integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
mixin-deep@^1.2.0:
version "1.3.2"
@@ -5395,12 +5883,22 @@
for-in "^1.0.2"
is-extendable "^1.0.1"
-mkdirp@^0.5.0, mkdirp@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
- integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4:
+ version "0.5.5"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
+ integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
- minimist "0.0.8"
+ minimist "^1.2.5"
+
+mkdirp@^1.0.0, mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+moment@^2.15.1, moment@^2.24.0:
+ version "2.29.1"
+ resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
+ integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
mout@^1.0.0:
version "1.2.2"
@@ -5417,20 +5915,25 @@
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-ms@^2.1.1:
+ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
multer@^1.3.0:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
- integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.3.tgz#4db352d6992e028ac0eacf7be45c6efd0264297b"
+ integrity sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==
dependencies:
append-field "^1.0.0"
busboy "^0.2.11"
concat-stream "^1.5.2"
- mkdirp "^0.5.1"
+ mkdirp "^0.5.4"
object-assign "^4.1.1"
on-finished "^2.3.0"
type-is "^1.6.4"
@@ -5446,6 +5949,17 @@
arrify "^1.0.0"
minimatch "^3.0.0"
+multimatch@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
+ integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
+ dependencies:
+ "@types/minimatch" "^3.0.3"
+ array-differ "^3.0.0"
+ array-union "^2.1.0"
+ arrify "^2.0.1"
+ minimatch "^3.0.4"
+
multipipe@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
@@ -5459,10 +5973,10 @@
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=
-mute-stream@0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
- integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+mute-stream@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
mz@^2.4.0, mz@^2.6.0:
version "2.7.0"
@@ -5474,9 +5988,9 @@
thenify-all "^1.0.0"
nan@^2.12.1:
- version "2.14.0"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
- integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+ version "2.15.0"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
+ integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
nanomatch@^1.2.9:
version "1.2.13"
@@ -5517,10 +6031,15 @@
dependencies:
lower-case "^1.1.1"
-node-fetch@^2.3.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
- integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
+node-fetch@^2.6.0, node-fetch@^2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
+ integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
+
+node-releases@^1.1.75:
+ version "1.1.75"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe"
+ integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==
node-status-codes@^1.0.0:
version "1.0.0"
@@ -5535,7 +6054,7 @@
chalk "~0.4.0"
underscore "~1.6.0"
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -5557,6 +6076,23 @@
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+normalize-url@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+ integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+npm-api@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/npm-api/-/npm-api-1.0.1.tgz#3def9b51afedca57db14ca0c970d92442d21c9c5"
+ integrity sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==
+ dependencies:
+ JSONStream "^1.3.5"
+ clone-deep "^4.0.1"
+ download-stats "^0.3.4"
+ moment "^2.24.0"
+ node-fetch "^2.6.0"
+ paged-request "^2.0.1"
+
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@@ -5564,6 +6100,13 @@
dependencies:
path-key "^2.0.0"
+npm-run-path@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
@@ -5579,11 +6122,6 @@
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-object-component@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
- integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=
-
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -5593,7 +6131,7 @@
define-property "^0.2.5"
kind-of "^3.0.3"
-object-keys@^1.0.11, object-keys@^1.0.12:
+object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
@@ -5606,14 +6144,14 @@
isobject "^3.0.0"
object.assign@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
- integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
+ integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
dependencies:
- define-properties "^1.1.2"
- function-bind "^1.1.1"
- has-symbols "^1.0.0"
- object-keys "^1.0.11"
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+ has-symbols "^1.0.1"
+ object-keys "^1.1.1"
object.omit@^2.0.0:
version "2.0.1"
@@ -5659,22 +6197,24 @@
dependencies:
wrappy "1"
-one-time@0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e"
- integrity sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
-onetime@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
- integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+onetime@^5.1.0:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
- mimic-fn "^1.0.0"
+ mimic-fn "^2.1.0"
opn@^3.0.2:
version "3.0.3"
@@ -5683,14 +6223,6 @@
dependencies:
object-assign "^4.0.1"
-optimist@^0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686"
- integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY=
- dependencies:
- minimist "~0.0.1"
- wordwrap "~0.0.2"
-
ordered-read-streams@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
@@ -5735,15 +6267,20 @@
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==
+p-cancelable@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
+ integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-limit@^2.0.0:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
- integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
@@ -5791,6 +6328,13 @@
registry-url "^3.0.3"
semver "^5.1.0"
+paged-request@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/paged-request/-/paged-request-2.0.2.tgz#4d621a08b8d6bee4440a0a92112354eeece5b5b0"
+ integrity sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==
+ dependencies:
+ axios "^0.21.1"
+
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
@@ -5828,6 +6372,16 @@
error-ex "^1.3.1"
json-parse-better-errors "^1.0.1"
+parse-json@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
parse-passwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
@@ -5863,19 +6417,15 @@
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
-parseqs@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
- integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=
- dependencies:
- better-assert "~1.0.0"
+parseqs@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5"
+ integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==
-parseuri@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
- integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=
- dependencies:
- better-assert "~1.0.0"
+parseuri@0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
+ integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
parseurl@~1.3.3:
version "1.3.3"
@@ -5919,10 +6469,15 @@
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-to-regexp@0.1.7:
version "0.1.7"
@@ -6312,15 +6867,10 @@
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
-pretty-bytes@^5.1.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
- integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
-
-private@^0.1.6:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
- integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+pretty-bytes@^5.1.0, pretty-bytes@^5.2.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
+ integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
version "2.0.1"
@@ -6352,22 +6902,22 @@
long "^4.0.0"
proxy-addr@~2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
- integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
dependencies:
- forwarded "~0.1.2"
- ipaddr.js "1.9.0"
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
pseudomap@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-psl@^1.1.24:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
- integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==
+psl@^1.1.24, psl@^1.1.28:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
+ integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
pump@^1.0.0:
version "1.0.3"
@@ -6407,7 +6957,7 @@
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-punycode@^2.1.0:
+punycode@^2.1.0, punycode@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
@@ -6427,6 +6977,11 @@
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
randomatic@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
@@ -6436,6 +6991,13 @@
kind-of "^6.0.0"
math-random "^1.0.1"
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
range-parser@~1.2.0, range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
@@ -6469,7 +7031,7 @@
pinkie-promise "^2.0.0"
readable-stream "^2.0.0"
-read-chunk@^3.0.0:
+read-chunk@^3.0.0, read-chunk@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
@@ -6493,6 +7055,14 @@
find-up "^3.0.0"
read-pkg "^3.0.0"
+read-pkg-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-5.0.0.tgz#b6a6741cb144ed3610554f40162aa07a6db621b8"
+ integrity sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==
+ dependencies:
+ find-up "^3.0.0"
+ read-pkg "^5.0.0"
+
read-pkg@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
@@ -6511,6 +7081,16 @@
normalize-package-data "^2.3.2"
path-type "^3.0.0"
+read-pkg@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
readable-stream@1.1.x:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@@ -6521,10 +7101,10 @@
isarray "0.0.1"
string_decoder "~0.10.x"
-"readable-stream@2 || 3", readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.5.0.tgz#465d70e6d1087f6162d079cd0b5db7fbebfd1606"
- integrity sha512-gSz026xs2LfxBPudDuI41V1lka8cxg64E66SGe78zJlsUofOg/yqwezdIcdfwik6B4h8LFmWPA9ef9X3FiNFLA==
+"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
+ integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
@@ -6540,7 +7120,7 @@
isarray "0.0.1"
string_decoder "~0.10.x"
-readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
+readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -6582,29 +7162,34 @@
resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
-regenerate-unicode-properties@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
- integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+regenerate-unicode-properties@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
+ integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
dependencies:
regenerate "^1.4.0"
regenerate@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
- integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
+ integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-regenerator-transform@^0.14.0:
- version "0.14.1"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb"
- integrity sha512-flVuee02C3FKRISbxhXl9mGzdbWUVHubl1SMaknjxkFB1/iqpJhArQUvRxOOPEc/9tAiX0BaQ28FJH10E4isSQ==
+regenerator-runtime@^0.13.4:
+ version "0.13.9"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
+ integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
+
+regenerator-transform@^0.14.2:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
+ integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
dependencies:
- private "^0.1.6"
+ "@babel/runtime" "^7.8.4"
regex-cache@^0.4.2:
version "0.4.4"
@@ -6621,17 +7206,17 @@
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
-regexpu-core@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6"
- integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg==
+regexpu-core@^4.7.1:
+ version "4.7.1"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
+ integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
dependencies:
regenerate "^1.4.0"
- regenerate-unicode-properties "^8.1.0"
- regjsgen "^0.5.0"
- regjsparser "^0.6.0"
+ regenerate-unicode-properties "^8.2.0"
+ regjsgen "^0.5.1"
+ regjsparser "^0.6.4"
unicode-match-property-ecmascript "^1.0.4"
- unicode-match-property-value-ecmascript "^1.1.0"
+ unicode-match-property-value-ecmascript "^1.2.0"
registry-auth-token@^3.0.1:
version "3.4.0"
@@ -6648,15 +7233,15 @@
dependencies:
rc "^1.0.1"
-regjsgen@^0.5.0:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c"
- integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==
+regjsgen@^0.5.1:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
+ integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
-regjsparser@^0.6.0:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.2.tgz#fd62c753991467d9d1ffe0a9f67f27a529024b96"
- integrity sha512-E9ghzUtoLwDekPT0DYCp+c4h+bvuUpe6rRHCTYn6eGoqj1LgKXxT6I0Il4WbjhQkOghzi/V+y03bPKvbllL93Q==
+regjsparser@^0.6.4:
+ version "0.6.9"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
+ integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
dependencies:
jsesc "~0.5.0"
@@ -6671,9 +7256,9 @@
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
repeat-element@^1.1.2:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
- integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
+ integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
repeat-string@^1.5.2, repeat-string@^1.6.1:
version "1.6.1"
@@ -6693,11 +7278,11 @@
integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
replace-ext@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
- integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
+ integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
-request@2.88.0, request@^2.72.0, request@^2.85.0:
+request@2.88.0:
version "2.88.0"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -6723,6 +7308,32 @@
tunnel-agent "^0.6.0"
uuid "^3.3.2"
+request@^2.72.0, request@^2.85.0:
+ version "2.88.2"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
+ integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.3"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.5.0"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
requirejs@^2.3.4:
version "2.3.6"
resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
@@ -6733,6 +7344,11 @@
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+resolve-alpn@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
+ integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
+
resolve-dir@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
@@ -6754,13 +7370,21 @@
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.3.2, resolve@^1.5.0:
- version "1.15.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
- integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
+resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.1, resolve@^1.5.0:
+ version "1.20.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
+ integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
+ is-core-module "^2.2.0"
path-parse "^1.0.6"
+responselike@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
+ integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
+ dependencies:
+ lowercase-keys "^2.0.0"
+
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@@ -6769,12 +7393,12 @@
exit-hook "^1.0.0"
onetime "^1.0.0"
-restore-cursor@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
- integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
dependencies:
- onetime "^2.0.0"
+ onetime "^5.1.0"
signal-exit "^3.0.2"
ret@~0.1.10:
@@ -6782,7 +7406,7 @@
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2:
+rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
@@ -6790,9 +7414,9 @@
glob "^7.1.3"
rimraf@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.0.tgz#614176d4b3010b75e5c390eb0ee96f6dc0cebb9b"
- integrity sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
@@ -6815,14 +7439,14 @@
rollup-pluginutils "^2.8.1"
rollup-plugin-terser@^5.1.3:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.2.0.tgz#ba758adf769347b7f1eaf9ef35978d2e207dccc7"
- integrity sha512-jQI+nYhtDBc9HFRBz8iGttQg7li9klmzR62RG2W2nN6hJ/FI2K2ItYQ7kJ7/zn+vs+BP1AEccmVRjRN989I+Nw==
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz#8c650062c22a8426c64268548957463bf981b413"
+ integrity sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w==
dependencies:
"@babel/code-frame" "^7.5.5"
jest-worker "^24.9.0"
rollup-pluginutils "^2.8.2"
- serialize-javascript "^2.1.2"
+ serialize-javascript "^4.0.0"
terser "^4.6.2"
rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2:
@@ -6833,37 +7457,35 @@
estree-walker "^0.6.1"
rollup@^1.3.0:
- version "1.30.0"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.30.0.tgz#ae9c893804e8eaa8f8f74b0aaf7e7fb4374a9d01"
- integrity sha512-ANcmfaSQwpcJtZUTA0ZMNBtFcQ1B4A5FldlNqEK0WdWm9sHSKu93ffa2KV1ux8HA/yKIV/ZARV28m7rNdXJgEw==
+ version "1.32.1"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4"
+ integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==
dependencies:
"@types/estree" "*"
"@types/node" "*"
acorn "^7.1.0"
rollup@^2.3.4:
- version "2.35.1"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c"
- integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==
+ version "2.56.3"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.3.tgz#b63edadd9851b0d618a6d0e6af8201955a77aeff"
+ integrity sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==
optionalDependencies:
- fsevents "~2.1.2"
+ fsevents "~2.3.2"
-run-async@^2.0.0, run-async@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
- integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
- dependencies:
- is-promise "^2.1.0"
+run-async@^2.0.0, run-async@^2.2.0, run-async@^2.4.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
-rxjs@^6.4.0:
- version "6.5.4"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
- integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
+rxjs@^6.4.0, rxjs@^6.6.0:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
+ integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
@@ -6872,10 +7494,10 @@
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
- integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-regex@^1.1.0:
version "1.1.0"
@@ -6895,13 +7517,13 @@
integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
sauce-connect-launcher@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.1.tgz#31137f57b0f7176e1c0525b7fb09c6da746647cf"
- integrity sha512-vIf9qDol3q2FlYzrKt0dr3kvec6LSjX2WS+/mVnAJIhqh1evSkPKCR2AzcJrnSmx9Xt9PtV0tLY7jYh0wsQi8A==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.2.tgz#dfc675a258550809a8eaf457eb9162b943ddbaf0"
+ integrity sha512-wf0coUlidJ7rmeClgVVBh6Kw55/yalZCY/Un5RgjSnTXRAeGqagnTsTYpZaqC4dCtrY4myuYpOAZXCdbO7lHfQ==
dependencies:
adm-zip "~0.4.3"
async "^2.1.2"
- https-proxy-agent "^3.0.0"
+ https-proxy-agent "^5.0.0"
lodash "^4.16.6"
rimraf "^2.5.4"
@@ -6916,22 +7538,21 @@
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
selenium-standalone@^6.7.0:
- version "6.17.0"
- resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.17.0.tgz#0f24b691836205ee9bc3d7a6f207ebcb28170cd9"
- integrity sha512-5PSnDHwMiq+OCiAGlhwQ8BM9xuwFfvBOZ7Tfbw+ifkTnOy0PWbZmI1B9gPGuyGHpbQ/3J3CzIK7BYwrQ7EjtWQ==
+ version "6.24.0"
+ resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.24.0.tgz#cca7c1c36bfa3429078a8e6a1a4fd373f641a7c8"
+ integrity sha512-Dun2XgNAgCfJNrrSzuv7Z7Wj7QTvBKpqx0VXFz7bW9T9FUe5ytzgzoCEEshwDVMh0Dv6sCgdZg7VDhM/q2yPPQ==
dependencies:
- async "^2.6.2"
- commander "^2.19.0"
- cross-spawn "^6.0.5"
- debug "^4.1.1"
- lodash "^4.17.11"
- minimist "^1.2.0"
- mkdirp "^0.5.1"
+ commander "^2.20.3"
+ cross-spawn "^7.0.3"
+ debug "^4.3.1"
+ got "^11.8.2"
+ lodash.mapvalues "^4.6.0"
+ lodash.merge "^4.6.2"
+ minimist "^1.2.5"
+ mkdirp "^1.0.4"
progress "2.0.3"
- request "2.88.0"
- tar-stream "2.0.0"
- urijs "^1.19.1"
- which "^1.3.1"
+ tar-stream "2.2.0"
+ which "^2.0.2"
yauzl "^2.10.0"
semver-diff@^2.0.0:
@@ -6941,7 +7562,7 @@
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0:
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -6951,11 +7572,18 @@
resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
-semver@^6.3.0:
+semver@^6.0.0, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+semver@^7.1.3, semver@^7.2.1:
+ version "7.3.5"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
+ integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
+ dependencies:
+ lru-cache "^6.0.0"
+
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@@ -6994,10 +7622,12 @@
range-parser "~1.2.0"
statuses "~1.4.0"
-serialize-javascript@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
- integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==
+serialize-javascript@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
+ integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
+ dependencies:
+ randombytes "^2.1.0"
serve-static@1.14.1:
version "1.14.1"
@@ -7019,6 +7649,13 @@
resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
+set-getter@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.1.tgz#a3110e1b461d31a9cfc8c5c9ee2e9737ad447102"
+ integrity sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==
+ dependencies:
+ to-object-path "^0.3.0"
+
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -7044,6 +7681,13 @@
resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
+shallow-clone@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
+ integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
+ dependencies:
+ kind-of "^6.0.2"
+
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -7051,24 +7695,36 @@
dependencies:
shebang-regex "^1.0.0"
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
-shelljs@^0.8.0:
- version "0.8.3"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.3.tgz#a7f3319520ebf09ee81275b2368adb286659b097"
- integrity sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shelljs@^0.8.0, shelljs@^0.8.4:
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
+ integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
dependencies:
glob "^7.0.0"
interpret "^1.0.0"
rechoir "^0.6.2"
signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
- integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+ integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
simple-swizzle@^0.2.2:
version "0.2.2"
@@ -7101,6 +7757,11 @@
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
+slash@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
+ integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
+
slide@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@@ -7141,54 +7802,51 @@
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
-socket.io-client@2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4"
- integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==
+socket.io-client@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
+ integrity sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==
dependencies:
backo2 "1.0.2"
- base64-arraybuffer "0.1.5"
component-bind "1.0.0"
- component-emitter "1.2.1"
- debug "~4.1.0"
- engine.io-client "~3.4.0"
+ component-emitter "~1.3.0"
+ debug "~3.1.0"
+ engine.io-client "~3.5.0"
has-binary2 "~1.0.2"
- has-cors "1.1.0"
indexof "0.0.1"
- object-component "0.0.3"
- parseqs "0.0.5"
- parseuri "0.0.5"
+ parseqs "0.0.6"
+ parseuri "0.0.6"
socket.io-parser "~3.3.0"
to-array "0.1.4"
socket.io-parser@~3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
- integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
+ integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
dependencies:
- component-emitter "1.2.1"
+ component-emitter "~1.3.0"
debug "~3.1.0"
isarray "2.0.1"
socket.io-parser@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a"
- integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.1.tgz#b06af838302975837eab2dc980037da24054d64a"
+ integrity sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==
dependencies:
component-emitter "1.2.1"
debug "~4.1.0"
isarray "2.0.1"
socket.io@^2.0.3:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb"
- integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2"
+ integrity sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==
dependencies:
debug "~4.1.0"
- engine.io "~3.4.0"
+ engine.io "~3.5.0"
has-binary2 "~1.0.2"
socket.io-adapter "~1.1.0"
- socket.io-client "2.3.0"
+ socket.io-client "2.4.0"
socket.io-parser "~3.4.0"
sort-keys-length@^1.0.0:
@@ -7225,17 +7883,17 @@
source-map "^0.6.0"
source-map-support@~0.5.12:
- version "0.5.16"
- resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042"
- integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==
+ version "0.5.19"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
+ integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-url@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
- integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
@@ -7256,30 +7914,30 @@
os-shim "^0.1.2"
spdx-correct@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
- integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+ integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
dependencies:
spdx-expression-parse "^3.0.0"
spdx-license-ids "^3.0.0"
spdx-exceptions@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
- integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+ integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
spdx-expression-parse@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
- integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.5"
- resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
- integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b"
+ integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==
spdy-transport@^2.0.18:
version "2.1.1"
@@ -7395,7 +8053,7 @@
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
-string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+string-width@^2.0.0, string-width@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
@@ -7403,6 +8061,15 @@
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
+string-width@^4.1.0:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
+ integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.0"
+
string_decoder@^1.1.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
@@ -7436,18 +8103,25 @@
dependencies:
ansi-regex "^3.0.0"
-strip-ansi@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
- integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+strip-ansi@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+ integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
dependencies:
- ansi-regex "^4.1.0"
+ ansi-regex "^5.0.0"
strip-ansi@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
+strip-bom-buf@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
+ integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=
+ dependencies:
+ is-utf8 "^0.2.1"
+
strip-bom-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
@@ -7481,6 +8155,11 @@
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
strip-indent@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
@@ -7518,9 +8197,9 @@
has-flag "^3.0.0"
supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
@@ -7581,12 +8260,12 @@
pump "^1.0.0"
tar-stream "^1.1.2"
-tar-stream@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.0.0.tgz#8829bbf83067bc0288a9089db49c56be395b6aea"
- integrity sha512-n2vtsWshZOVr/SY4KtslPoUlyNh06I2SGgAOCZmquCEjlbV/LjY2CY80rDtdQRHFOYXNlgBDo6Fr3ww2CWPOtA==
+tar-stream@2.2.0, tar-stream@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+ integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
dependencies:
- bl "^2.2.0"
+ bl "^4.0.3"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
@@ -7605,17 +8284,6 @@
to-buffer "^1.1.1"
xtend "^4.0.0"
-tar-stream@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
- integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
- dependencies:
- bl "^3.0.0"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
temp@^0.8.1, temp@^0.8.3:
version "0.8.4"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
@@ -7641,9 +8309,9 @@
through2 "^2.0.1"
terser@^4.6.2:
- version "4.6.3"
- resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
- integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
+ version "4.8.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
+ integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"
@@ -7685,9 +8353,9 @@
thenify ">= 3.1.0 < 4"
"thenify@>= 3.1.0 < 4":
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
- integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
dependencies:
any-promise "^1.0.0"
@@ -7723,14 +8391,15 @@
readable-stream "~2.3.6"
xtend "~4.0.1"
-through2@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a"
- integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==
+through2@^3.0.0, through2@^3.0.1, through2@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4"
+ integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==
dependencies:
+ inherits "^2.0.4"
readable-stream "2 || 3"
-through@^2.3.6:
+"through@>=2.2.7 <3", through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -7824,6 +8493,14 @@
psl "^1.1.24"
punycode "^1.4.1"
+tough-cookie@~2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
+ integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
+ dependencies:
+ psl "^1.1.28"
+ punycode "^2.1.1"
+
tr46@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
@@ -7846,16 +8523,11 @@
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
-tslib@^1.8.1:
+tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-tslib@^1.9.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
- integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
-
tsutils@2.27.2:
version "2.27.2"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
@@ -7880,6 +8552,16 @@
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@@ -7909,9 +8591,9 @@
integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
ua-parser-js@^0.7.15:
- version "0.7.21"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777"
- integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==
+ version "0.7.28"
+ resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
+ integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
uglify-js@3.4.x:
version "3.4.10"
@@ -7922,9 +8604,9 @@
source-map "~0.6.1"
underscore@^1.8.3:
- version "1.9.2"
- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
- integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1"
+ integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==
underscore@~1.6.0:
version "1.6.0"
@@ -7944,15 +8626,15 @@
unicode-canonical-property-names-ecmascript "^1.0.4"
unicode-property-aliases-ecmascript "^1.0.4"
-unicode-match-property-value-ecmascript@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
- integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+unicode-match-property-value-ecmascript@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
+ integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
unicode-property-aliases-ecmascript@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
- integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
+ integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
union-value@^1.0.0:
version "1.0.1"
@@ -7980,12 +8662,17 @@
crypto-random-string "^1.0.0"
universal-user-agent@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16"
- integrity sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA==
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557"
+ integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==
dependencies:
os-name "^3.1.0"
+universal-user-agent@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
+ integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
+
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
@@ -8057,16 +8744,16 @@
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
-urijs@^1.16.1, urijs@^1.19.1:
- version "1.19.2"
- resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a"
- integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==
+urijs@^1.16.1:
+ version "1.19.7"
+ resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.7.tgz#4f594e59113928fea63c00ce688fb395b1168ab9"
+ integrity sha512-Id+IKjdU0Hx+7Zx717jwLPsPeUqz7rAtuVBRLLs+qn+J2nf9NGITWVCxcijgYxBqe83C7sqsQPs6H1pyz3x9gA==
urix@^0.1.0:
version "0.1.0"
@@ -8151,17 +8838,16 @@
core-util-is "1.0.2"
extsprintf "^1.2.0"
-vinyl-file@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a"
- integrity sha1-p+v1/779obfRjRQPyweyI++2dRo=
+vinyl-file@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
+ integrity sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=
dependencies:
graceful-fs "^4.1.2"
pify "^2.3.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
+ strip-bom-buf "^1.0.0"
strip-bom-stream "^2.0.0"
- vinyl "^1.1.0"
+ vinyl "^2.0.1"
vinyl-fs@^2.4.3, vinyl-fs@^2.4.4:
version "2.4.4"
@@ -8186,7 +8872,7 @@
vali-date "^1.0.0"
vinyl "^1.0.0"
-vinyl@^1.0.0, vinyl@^1.1.0, vinyl@^1.1.1, vinyl@^1.2.0:
+vinyl@^1.0.0, vinyl@^1.1.1, vinyl@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
@@ -8195,10 +8881,10 @@
clone-stats "^0.0.1"
replace-ext "0.0.1"
-vinyl@^2.0.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86"
- integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==
+vinyl@^2.0.1, vinyl@^2.2.0, vinyl@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
+ integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
dependencies:
clone "^2.1.1"
clone-buffer "^1.0.0"
@@ -8254,9 +8940,9 @@
uuid "^3.2.1"
wd@^1.2.0:
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/wd/-/wd-1.12.1.tgz#067eb3674db00eeb9e506701f9314657c44d5a89"
- integrity sha512-O99X8OnOgkqfmsPyLIRzG9LmZ+rjmdGFBCyhGpnsSL4MB4xzHoeWmSVcumDiQ5QqPZcwGkszTgeJvjk2VjtiNw==
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/wd/-/wd-1.14.0.tgz#1fe6450b5baef37caa135e7755292c6998ca8a90"
+ integrity sha512-X7ZfGHHYlQ5zYpRlgP16LUsvYti+Al/6fz3T/ClVyivVCpCZQpESTDdz6zbK910O5OIvujO23Ym2DBBo3XsQlA==
dependencies:
archiver "^3.0.0"
async "^2.0.0"
@@ -8315,14 +9001,14 @@
tr46 "^1.0.1"
webidl-conversions "^4.0.2"
-which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
-which@^2.0.2:
+which@^2.0.1, which@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
@@ -8344,34 +9030,34 @@
string-width "^2.1.1"
windows-release@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
- integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999"
+ integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==
dependencies:
execa "^1.0.0"
-winston-transport@^4.2.0, winston-transport@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.3.0.tgz#df68c0c202482c448d9b47313c07304c2d7c2c66"
- integrity sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==
+winston-transport@^4.2.0, winston-transport@^4.4.0:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59"
+ integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==
dependencies:
- readable-stream "^2.3.6"
+ readable-stream "^2.3.7"
triple-beam "^1.2.0"
winston@^3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/winston/-/winston-3.2.1.tgz#63061377976c73584028be2490a1846055f77f07"
- integrity sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==
+ version "3.3.3"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"
+ integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==
dependencies:
- async "^2.6.1"
- diagnostics "^1.1.1"
- is-stream "^1.1.0"
- logform "^2.1.1"
- one-time "0.0.4"
- readable-stream "^3.1.1"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.1.0"
+ is-stream "^2.0.0"
+ logform "^2.2.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
stack-trace "0.0.x"
triple-beam "^1.3.0"
- winston-transport "^4.3.0"
+ winston-transport "^4.4.0"
with-open-file@^0.1.6:
version "0.1.7"
@@ -8382,7 +9068,7 @@
p-try "^2.1.0"
pify "^4.0.1"
-wordwrap@~0.0.2:
+wordwrap@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
@@ -8428,17 +9114,10 @@
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
-ws@^7.1.2:
- version "7.2.1"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
- integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
-
-ws@~6.1.0:
- version "6.1.4"
- resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9"
- integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==
- dependencies:
- async-limiter "~1.0.0"
+ws@~7.4.2:
+ version "7.4.6"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
+ integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
xdg-basedir@^2.0.0:
version "2.0.0"
@@ -8462,10 +9141,10 @@
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
-xmlhttprequest-ssl@~1.5.4:
- version "1.5.5"
- resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
- integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
+xmlhttprequest-ssl@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz#03b713873b01659dfa2c1c5d056065b27ddc2de6"
+ integrity sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q==
"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
version "4.0.2"
@@ -8477,6 +9156,11 @@
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
yauzl@^2.10.0:
version "2.10.0"
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
@@ -8508,26 +9192,30 @@
text-table "^0.2.0"
untildify "^2.0.0"
-yeoman-environment@^2.0.5:
- version "2.7.0"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.7.0.tgz#d1b6679de883ce14a68b869c4b19d55a0d66f477"
- integrity sha512-YNzSUWgJVSgnm0qgLON4Gb2nTm+kywBiWjK4MbvosjUP2YJJ30lNhEx7ukyzKRPUlsavd5IsuALtF6QaVrq81A==
+yeoman-environment@^2.0.5, yeoman-environment@^2.9.5:
+ version "2.10.3"
+ resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.10.3.tgz#9d8f42b77317414434cc0e51fb006a4bdd54688e"
+ integrity sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==
dependencies:
chalk "^2.4.1"
- cross-spawn "^6.0.5"
debug "^3.1.0"
diff "^3.5.0"
escape-string-regexp "^1.0.2"
+ execa "^4.0.0"
globby "^8.0.1"
- grouped-queue "^0.3.3"
- inquirer "^6.0.0"
+ grouped-queue "^1.1.0"
+ inquirer "^7.1.0"
is-scoped "^1.0.0"
lodash "^4.17.10"
log-symbols "^2.2.0"
mem-fs "^1.1.0"
+ mem-fs-editor "^6.0.0"
+ npm-api "^1.0.0"
+ semver "^7.1.3"
strip-ansi "^4.0.0"
text-table "^0.2.0"
untildify "^3.0.3"
+ yeoman-generator "^4.8.2"
yeoman-generator@^3.1.1:
version "3.2.0"
@@ -8560,6 +9248,40 @@
through2 "^3.0.0"
yeoman-environment "^2.0.5"
+yeoman-generator@^4.8.2:
+ version "4.13.0"
+ resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-4.13.0.tgz#a6caeed8491fceea1f84f53e31795f25888b4672"
+ integrity sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==
+ dependencies:
+ async "^2.6.2"
+ chalk "^2.4.2"
+ cli-table "^0.3.1"
+ cross-spawn "^6.0.5"
+ dargs "^6.1.0"
+ dateformat "^3.0.3"
+ debug "^4.1.1"
+ diff "^4.0.1"
+ error "^7.0.2"
+ find-up "^3.0.0"
+ github-username "^3.0.0"
+ istextorbinary "^2.5.1"
+ lodash "^4.17.11"
+ make-dir "^3.0.0"
+ mem-fs-editor "^7.0.1"
+ minimist "^1.2.5"
+ pretty-bytes "^5.2.0"
+ read-chunk "^3.2.0"
+ read-pkg-up "^5.0.0"
+ rimraf "^2.6.3"
+ run-async "^2.0.0"
+ semver "^7.2.1"
+ shelljs "^0.8.4"
+ text-table "^0.2.0"
+ through2 "^3.0.1"
+ optionalDependencies:
+ grouped-queue "^1.1.0"
+ yeoman-environment "^2.9.5"
+
zip-stream@^2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
diff --git a/tools/polygerrit-updater/tsconfig.json b/tools/polygerrit-updater/tsconfig.json
index 37ff1b2..80f60c1 100644
--- a/tools/polygerrit-updater/tsconfig.json
+++ b/tools/polygerrit-updater/tsconfig.json
@@ -2,8 +2,8 @@
"compilerOptions": {
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
- "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
- "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
+ "target": "es2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
+ "module": "es2015", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
diff --git a/twinkie.patch b/twinkie.patch
deleted file mode 100644
index 0a61243..0000000
--- a/twinkie.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/node_modules/twinkie/src/app/index.js
-+++ b/node_modules/twinkie/src/app/index.js
-@@ -250,7 +250,7 @@ twinkie --tsconfig tsconfig.json --outdir output_dir [--files file_list] [--outt
- incremental: false,
- noEmit: true,
- },
-- files: [...allProgramFilesNames, generatedFiles],
-+ files: [...allProgramFilesNames, ...generatedFiles],
- };
- fs.writeFileSync(cmdLineOptions.outputTsConfig, JSON.stringify(tsconfigContent, null, 2));
- }
diff --git a/yarn.lock b/yarn.lock
index 32d86fc..17c08c3 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,727 +2,127 @@
# yarn lockfile v1
-"@babel/code-frame@7.12.11", "@babel/code-frame@^7.0.0":
+"@babel/code-frame@7.12.11":
version "7.12.11"
- resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
dependencies:
"@babel/highlight" "^7.10.4"
-"@babel/code-frame@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658"
- integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==
+"@babel/code-frame@^7.0.0":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
+ integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
dependencies:
- "@babel/highlight" "^7.12.13"
+ "@babel/highlight" "^7.14.5"
-"@babel/compat-data@^7.13.12", "@babel/compat-data@^7.13.8":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.15.tgz#7e8eea42d0b64fda2b375b22d06c605222e848f4"
- integrity sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==
+"@babel/helper-validator-identifier@^7.14.5":
+ version "7.14.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
+ integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
-"@babel/core@^7.0.0":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.15.tgz#a6d40917df027487b54312202a06812c4f7792d0"
- integrity sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==
+"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
+ integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
dependencies:
- "@babel/code-frame" "^7.12.13"
- "@babel/generator" "^7.13.9"
- "@babel/helper-compilation-targets" "^7.13.13"
- "@babel/helper-module-transforms" "^7.13.14"
- "@babel/helpers" "^7.13.10"
- "@babel/parser" "^7.13.15"
- "@babel/template" "^7.12.13"
- "@babel/traverse" "^7.13.15"
- "@babel/types" "^7.13.14"
- convert-source-map "^1.7.0"
- debug "^4.1.0"
- gensync "^1.0.0-beta.2"
- json5 "^2.1.2"
- semver "^6.3.0"
- source-map "^0.5.0"
-
-"@babel/generator@^7.0.0-beta.42", "@babel/generator@^7.13.9":
- version "7.13.9"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39"
- integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==
- dependencies:
- "@babel/types" "^7.13.0"
- jsesc "^2.5.1"
- source-map "^0.5.0"
-
-"@babel/helper-annotate-as-pure@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab"
- integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==
- dependencies:
- "@babel/types" "^7.12.13"
-
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc"
- integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==
- dependencies:
- "@babel/helper-explode-assignable-expression" "^7.12.13"
- "@babel/types" "^7.12.13"
-
-"@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8":
- version "7.13.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz#2b2972a0926474853f41e4adbc69338f520600e5"
- integrity sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==
- dependencies:
- "@babel/compat-data" "^7.13.12"
- "@babel/helper-validator-option" "^7.12.17"
- browserslist "^4.14.5"
- semver "^6.3.0"
-
-"@babel/helper-create-regexp-features-plugin@^7.12.13":
- version "7.12.17"
- resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz#a2ac87e9e319269ac655b8d4415e94d38d663cb7"
- integrity sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.12.13"
- regexpu-core "^4.7.1"
-
-"@babel/helper-explode-assignable-expression@^7.12.13":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f"
- integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==
- dependencies:
- "@babel/types" "^7.13.0"
-
-"@babel/helper-function-name@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a"
- integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==
- dependencies:
- "@babel/helper-get-function-arity" "^7.12.13"
- "@babel/template" "^7.12.13"
- "@babel/types" "^7.12.13"
-
-"@babel/helper-get-function-arity@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583"
- integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==
- dependencies:
- "@babel/types" "^7.12.13"
-
-"@babel/helper-member-expression-to-functions@^7.13.12":
- version "7.13.12"
- resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72"
- integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==
- dependencies:
- "@babel/types" "^7.13.12"
-
-"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
- version "7.13.12"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
- integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
- dependencies:
- "@babel/types" "^7.13.12"
-
-"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.13.14":
- version "7.13.14"
- resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz#e600652ba48ccb1641775413cb32cfa4e8b495ef"
- integrity sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==
- dependencies:
- "@babel/helper-module-imports" "^7.13.12"
- "@babel/helper-replace-supers" "^7.13.12"
- "@babel/helper-simple-access" "^7.13.12"
- "@babel/helper-split-export-declaration" "^7.12.13"
- "@babel/helper-validator-identifier" "^7.12.11"
- "@babel/template" "^7.12.13"
- "@babel/traverse" "^7.13.13"
- "@babel/types" "^7.13.14"
-
-"@babel/helper-optimise-call-expression@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea"
- integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==
- dependencies:
- "@babel/types" "^7.12.13"
-
-"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af"
- integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==
-
-"@babel/helper-remap-async-to-generator@^7.13.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209"
- integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.12.13"
- "@babel/helper-wrap-function" "^7.13.0"
- "@babel/types" "^7.13.0"
-
-"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.13.12":
- version "7.13.12"
- resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804"
- integrity sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==
- dependencies:
- "@babel/helper-member-expression-to-functions" "^7.13.12"
- "@babel/helper-optimise-call-expression" "^7.12.13"
- "@babel/traverse" "^7.13.0"
- "@babel/types" "^7.13.12"
-
-"@babel/helper-simple-access@^7.13.12":
- version "7.13.12"
- resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6"
- integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==
- dependencies:
- "@babel/types" "^7.13.12"
-
-"@babel/helper-skip-transparent-expression-wrappers@^7.12.1":
- version "7.12.1"
- resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf"
- integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==
- dependencies:
- "@babel/types" "^7.12.1"
-
-"@babel/helper-split-export-declaration@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05"
- integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==
- dependencies:
- "@babel/types" "^7.12.13"
-
-"@babel/helper-validator-identifier@^7.12.11":
- version "7.12.11"
- resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz"
- integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
-
-"@babel/helper-validator-option@^7.12.17":
- version "7.12.17"
- resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831"
- integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==
-
-"@babel/helper-wrap-function@^7.13.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4"
- integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==
- dependencies:
- "@babel/helper-function-name" "^7.12.13"
- "@babel/template" "^7.12.13"
- "@babel/traverse" "^7.13.0"
- "@babel/types" "^7.13.0"
-
-"@babel/helpers@^7.13.10":
- version "7.13.10"
- resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8"
- integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==
- dependencies:
- "@babel/template" "^7.12.13"
- "@babel/traverse" "^7.13.0"
- "@babel/types" "^7.13.0"
-
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13":
- version "7.13.10"
- resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz"
- integrity sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==
- dependencies:
- "@babel/helper-validator-identifier" "^7.12.11"
+ "@babel/helper-validator-identifier" "^7.14.5"
chalk "^2.0.0"
js-tokens "^4.0.0"
-"@babel/parser@^7.12.13", "@babel/parser@^7.13.15":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.15.tgz#8e66775fb523599acb6a289e12929fa5ab0954d8"
- integrity sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==
-
-"@babel/plugin-external-helpers@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.12.13.tgz#65ef9f4576297250dc601d2aa334769790d9966d"
- integrity sha512-ClvAsk4RqpE6iacYUjdU9PtvIwC9yAefZENsPfGeG5FckX3jFZLDlWPuyv5gi9/9C2VgwX6H8q1ukBifC0ha+Q==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-proposal-async-generator-functions@^7.0.0":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz#80e549df273a3b3050431b148c892491df1bcc5b"
- integrity sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/helper-remap-async-to-generator" "^7.13.0"
- "@babel/plugin-syntax-async-generators" "^7.8.4"
-
-"@babel/plugin-proposal-object-rest-spread@^7.0.0":
- version "7.13.8"
- resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz#5d210a4d727d6ce3b18f9de82cc99a3964eed60a"
- integrity sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==
- dependencies:
- "@babel/compat-data" "^7.13.8"
- "@babel/helper-compilation-targets" "^7.13.8"
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
- "@babel/plugin-transform-parameters" "^7.13.0"
-
-"@babel/plugin-syntax-async-generators@^7.0.0", "@babel/plugin-syntax-async-generators@^7.8.4":
- version "7.8.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
- integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-dynamic-import@^7.0.0":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
- integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-syntax-import-meta@^7.0.0":
- version "7.10.4"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
- integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
- dependencies:
- "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-object-rest-spread@^7.0.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3":
- version "7.8.3"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
- integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.8.0"
-
-"@babel/plugin-transform-arrow-functions@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae"
- integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-async-to-generator@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f"
- integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==
- dependencies:
- "@babel/helper-module-imports" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/helper-remap-async-to-generator" "^7.13.0"
-
-"@babel/plugin-transform-block-scoped-functions@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4"
- integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-block-scoping@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz#f36e55076d06f41dfd78557ea039c1b581642e61"
- integrity sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-classes@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz#0265155075c42918bf4d3a4053134176ad9b533b"
- integrity sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==
- dependencies:
- "@babel/helper-annotate-as-pure" "^7.12.13"
- "@babel/helper-function-name" "^7.12.13"
- "@babel/helper-optimise-call-expression" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/helper-replace-supers" "^7.13.0"
- "@babel/helper-split-export-declaration" "^7.12.13"
- globals "^11.1.0"
-
-"@babel/plugin-transform-computed-properties@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed"
- integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-destructuring@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz#c5dce270014d4e1ebb1d806116694c12b7028963"
- integrity sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-duplicate-keys@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de"
- integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-exponentiation-operator@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1"
- integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==
- dependencies:
- "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-for-of@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062"
- integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-function-name@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051"
- integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==
- dependencies:
- "@babel/helper-function-name" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-instanceof@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.12.13.tgz#5df8ead82ed421b728662c9e0ed943536c872ced"
- integrity sha512-lYZ6F2xmM797Nk8PzDn2AreAEjKb96S3JkZkaMUlRTIThaYjvo1+aLa7oegnVc42lJY7Hr4yT1M/i6kwRcPlsQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-literals@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9"
- integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-modules-amd@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz#19f511d60e3d8753cc5a6d4e775d3a5184866cc3"
- integrity sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==
- dependencies:
- "@babel/helper-module-transforms" "^7.13.0"
- "@babel/helper-plugin-utils" "^7.13.0"
- babel-plugin-dynamic-import-node "^2.3.3"
-
-"@babel/plugin-transform-object-super@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7"
- integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
- "@babel/helper-replace-supers" "^7.12.13"
-
-"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.13.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz#8fa7603e3097f9c0b7ca1a4821bc2fb52e9e5007"
- integrity sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-regenerator@^7.0.0":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39"
- integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==
- dependencies:
- regenerator-transform "^0.14.2"
-
-"@babel/plugin-transform-shorthand-properties@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad"
- integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-spread@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd"
- integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
- "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1"
-
-"@babel/plugin-transform-sticky-regex@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f"
- integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-template-literals@^7.0.0":
- version "7.13.0"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d"
- integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==
- dependencies:
- "@babel/helper-plugin-utils" "^7.13.0"
-
-"@babel/plugin-transform-typeof-symbol@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f"
- integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==
- dependencies:
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/plugin-transform-unicode-regex@^7.0.0":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac"
- integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==
- dependencies:
- "@babel/helper-create-regexp-features-plugin" "^7.12.13"
- "@babel/helper-plugin-utils" "^7.12.13"
-
-"@babel/runtime@^7.8.4":
- version "7.13.10"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.10.tgz#47d42a57b6095f4468da440388fdbad8bebf0d7d"
- integrity sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==
- dependencies:
- regenerator-runtime "^0.13.4"
-
-"@babel/template@^7.12.13":
- version "7.12.13"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
- integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==
- dependencies:
- "@babel/code-frame" "^7.12.13"
- "@babel/parser" "^7.12.13"
- "@babel/types" "^7.12.13"
-
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0-beta.42", "@babel/traverse@^7.13.0", "@babel/traverse@^7.13.13", "@babel/traverse@^7.13.15":
- version "7.13.15"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.15.tgz#c38bf7679334ddd4028e8e1f7b3aa5019f0dada7"
- integrity sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==
- dependencies:
- "@babel/code-frame" "^7.12.13"
- "@babel/generator" "^7.13.9"
- "@babel/helper-function-name" "^7.12.13"
- "@babel/helper-split-export-declaration" "^7.12.13"
- "@babel/parser" "^7.13.15"
- "@babel/types" "^7.13.14"
- debug "^4.1.0"
- globals "^11.1.0"
-
-"@babel/types@^7.0.0-beta.42", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.14":
- version "7.13.14"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
- integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
- dependencies:
- "@babel/helper-validator-identifier" "^7.12.11"
- lodash "^4.17.19"
- to-fast-properties "^2.0.0"
-
"@bazel/rollup@^3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.5.0.tgz#3de2db08cbc62c3cffbbabaa4517ec250cf6419a"
- integrity sha512-sFPqbzSbIn6h66uuZdXgK5oitSmEGtnDPfL3TwTS4ZWy75SpYvk9X1TFGlvkralEkVnFfdH15sq80/1t+YgQow==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@bazel/rollup/-/rollup-3.8.0.tgz#850f56176d73e3b7d99a43c7e33df21ecc6ac161"
+ integrity sha512-u63ubqYtfQhOu8Km3uYdhKa6qiLSlOKYsWwMP1xGkkXzu1hOiUznN1N7q8gCF1BV2DMy1D5IYkv+Xg4a+LEiBA==
"@bazel/terser@^3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-3.5.0.tgz#4b1c3a3b781e65547694aa05bc600c251e4d8c0b"
- integrity sha512-dpWHn1Iu+w0uA/kvPb0pP+4Io0PrVuzCCbVg2Ow4uRt/gTFKQJJWp4EiTitEZlPA2dHlW7PHThAb93lGo2c8qA==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@bazel/terser/-/terser-3.8.0.tgz#96d337b62b2ba18e2fe00984cca950cda899d165"
+ integrity sha512-c7cGIltFUI7prRocMDZ3qZVERnew81SFheuI5B9RQ3qeqTlJmlV8B8GI9FPG+7Ut69bmwn8es6UyPaH0iBnsQw==
"@bazel/typescript@^3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.5.0.tgz#605493f4f0a5297df8a7fcccb86a1a80ea2090bb"
- integrity sha512-BtGFp4nYFkQTmnONCzomk7dkmOwaINBL3piq+lykBlcc6UxLe9iCAnZpOyPypB1ReN3k3SRNAa53x6oGScQxMg==
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-3.8.0.tgz#725d51a1c25e314a1d8cddb8b880ac05ba97acd4"
+ integrity sha512-4C1pLe4V7aidWqcPsWNqXFS7uHAB1nH5SUKG5uWoVv4JT9XhkNSvzzQIycMwXs2tZeCylX4KYNeNvfKrmkyFlw==
dependencies:
protobufjs "6.8.8"
semver "5.6.0"
source-map-support "0.5.9"
tsutils "2.27.2"
-"@dabh/diagnostics@^2.0.2":
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31"
- integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==
- dependencies:
- colorspace "1.1.x"
- enabled "2.0.x"
- kuler "^2.0.0"
-
-"@eslint/eslintrc@^0.4.0":
- version "0.4.0"
- resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz"
- integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==
+"@eslint/eslintrc@^0.4.3":
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
+ integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
dependencies:
ajv "^6.12.4"
debug "^4.1.1"
espree "^7.3.0"
- globals "^12.1.0"
+ globals "^13.9.0"
ignore "^4.0.6"
import-fresh "^3.2.1"
js-yaml "^3.13.1"
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
-"@mrmlnc/readdir-enhanced@^2.2.1":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
- integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==
+"@humanwhocodes/config-array@^0.5.0":
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
+ integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
dependencies:
- call-me-maybe "^1.0.1"
- glob-to-regexp "^0.3.0"
+ "@humanwhocodes/object-schema" "^1.2.0"
+ debug "^4.1.1"
+ minimatch "^3.0.4"
-"@nodelib/fs.scandir@2.1.4":
- version "2.1.4"
- resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz"
- integrity sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==
+"@humanwhocodes/object-schema@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
+ integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
dependencies:
- "@nodelib/fs.stat" "2.0.4"
+ "@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
-"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2":
- version "2.0.4"
- resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz"
- integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==
-
-"@nodelib/fs.stat@^1.1.2":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
- integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
"@nodelib/fs.walk@^1.2.3":
- version "1.2.6"
- resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz"
- integrity sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
dependencies:
- "@nodelib/fs.scandir" "2.1.4"
+ "@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@octokit/auth-token@^2.4.0":
- version "2.4.5"
- resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.5.tgz#568ccfb8cb46f36441fac094ce34f7a875b197f3"
- integrity sha512-BpGYsPgJt05M7/L/5FoE1PiAbdxXFZkX/3kDYcsvd1v6UhlnE5e96dTDr0ezX/EFwciQxf3cNV0loipsURU+WA==
- dependencies:
- "@octokit/types" "^6.0.3"
-
-"@octokit/endpoint@^6.0.1":
- version "6.0.11"
- resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.11.tgz#082adc2aebca6dcefa1fb383f5efb3ed081949d1"
- integrity sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==
- dependencies:
- "@octokit/types" "^6.0.3"
- is-plain-object "^5.0.0"
- universal-user-agent "^6.0.0"
-
-"@octokit/openapi-types@^6.0.0":
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-6.0.0.tgz#7da8d7d5a72d3282c1a3ff9f951c8133a707480d"
- integrity sha512-CnDdK7ivHkBtJYzWzZm7gEkanA7gKH6a09Eguz7flHw//GacPJLmkHA3f3N++MJmlxD1Fl+mB7B32EEpSCwztQ==
-
-"@octokit/plugin-paginate-rest@^1.1.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc"
- integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==
- dependencies:
- "@octokit/types" "^2.0.1"
-
-"@octokit/plugin-request-log@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
- integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
-
-"@octokit/plugin-rest-endpoint-methods@2.4.0":
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e"
- integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==
- dependencies:
- "@octokit/types" "^2.0.1"
- deprecation "^2.3.1"
-
-"@octokit/request-error@^1.0.2":
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801"
- integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==
- dependencies:
- "@octokit/types" "^2.0.0"
- deprecation "^2.0.0"
- once "^1.4.0"
-
-"@octokit/request-error@^2.0.0":
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.0.5.tgz#72cc91edc870281ad583a42619256b380c600143"
- integrity sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==
- dependencies:
- "@octokit/types" "^6.0.3"
- deprecation "^2.0.0"
- once "^1.4.0"
-
-"@octokit/request@^5.2.0":
- version "5.4.15"
- resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.4.15.tgz#829da413dc7dd3aa5e2cdbb1c7d0ebe1f146a128"
- integrity sha512-6UnZfZzLwNhdLRreOtTkT9n57ZwulCve8q3IT/Z477vThu6snfdkBuhxnChpOKNGxcQ71ow561Qoa6uqLdPtag==
- dependencies:
- "@octokit/endpoint" "^6.0.1"
- "@octokit/request-error" "^2.0.0"
- "@octokit/types" "^6.7.1"
- is-plain-object "^5.0.0"
- node-fetch "^2.6.1"
- universal-user-agent "^6.0.0"
-
-"@octokit/rest@^16.2.0":
- version "16.43.2"
- resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b"
- integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==
- dependencies:
- "@octokit/auth-token" "^2.4.0"
- "@octokit/plugin-paginate-rest" "^1.1.1"
- "@octokit/plugin-request-log" "^1.0.0"
- "@octokit/plugin-rest-endpoint-methods" "2.4.0"
- "@octokit/request" "^5.2.0"
- "@octokit/request-error" "^1.0.2"
- atob-lite "^2.0.0"
- before-after-hook "^2.0.0"
- btoa-lite "^1.0.0"
- deprecation "^2.0.0"
- lodash.get "^4.4.2"
- lodash.set "^4.3.2"
- lodash.uniq "^4.5.0"
- octokit-pagination-methods "^1.1.0"
- once "^1.4.0"
- universal-user-agent "^4.0.0"
-
-"@octokit/types@^2.0.0", "@octokit/types@^2.0.1":
- version "2.16.2"
- resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2"
- integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==
- dependencies:
- "@types/node" ">= 8"
-
-"@octokit/types@^6.0.3", "@octokit/types@^6.7.1":
- version "6.13.0"
- resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.13.0.tgz#779e5b7566c8dde68f2f6273861dd2f0409480d0"
- integrity sha512-W2J9qlVIU11jMwKHUp5/rbVUeErqelCsO5vW5PKNb7wAXQVUz87Rc+imjlEvpvbH8yUb+KHmv8NEjVZdsdpyxA==
- dependencies:
- "@octokit/openapi-types" "^6.0.0"
-
-"@polymer/esm-amd-loader@^1.0.0":
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/@polymer/esm-amd-loader/-/esm-amd-loader-1.0.4.tgz#4e77f2f59b29b01e0ad02aa83d33716cddc5f9f9"
- integrity sha512-h+hqYkL+tQV/y2ESD5gFXMl5z4cC+XY1jTlBeGSBaTcj3VbB5OBEScbvRXm63NcEbBneQQYbHfBAXAkF9i9wIA==
-
-"@polymer/sinonjs@^1.14.1":
- version "1.17.1"
- resolved "https://registry.yarnpkg.com/@polymer/sinonjs/-/sinonjs-1.17.1.tgz#e47d3785b7d0e8c29feb97f7e924b0fc597e2e9b"
- integrity sha512-/U8F/cOTrbF2iVVYgINYmvKbtbexs+89Q3v8AaHADRYabTg7aOZGOb0RyWpOI+sUJt04kj63U4FwMhzW5r4wZA==
-
-"@polymer/test-fixture@^0.0.3":
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/@polymer/test-fixture/-/test-fixture-0.0.3.tgz#4443752697d4d9293bbc412ea0b5e4d341f149d9"
- integrity sha1-REN1JpfU2Sk7vEEuoLXk00HxSdk=
-
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
- resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
"@protobufjs/base64@^1.1.2":
version "1.1.2"
- resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
- resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
- resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
- resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
dependencies:
"@protobufjs/aspromise" "^1.1.1"
@@ -730,314 +130,41 @@
"@protobufjs/float@^1.0.2":
version "1.0.2"
- resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
- resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
"@protobufjs/path@^1.1.2":
version "1.1.2"
- resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
"@protobufjs/pool@^1.1.0":
version "1.1.0"
- resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
- resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@sindresorhus/is@^0.14.0":
version "0.14.0"
- resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
-"@sindresorhus/is@^4.0.0":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4"
- integrity sha512-FyD2meJpDPjyNQejSjvnhpgI/azsQkA4lGbuu5BQZfjvJ9cbRZXzeWL2HceCekW4lixO9JPesIIQkSoLjeJHNQ==
-
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
- resolved "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
dependencies:
defer-to-connect "^1.0.1"
-"@szmarczak/http-timer@^4.0.5":
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.5.tgz#bfbd50211e9dfa51ba07da58a14cdfd333205152"
- integrity sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==
- dependencies:
- defer-to-connect "^2.0.0"
-
-"@types/babel-generator@^6.25.1":
- version "6.25.3"
- resolved "https://registry.yarnpkg.com/@types/babel-generator/-/babel-generator-6.25.3.tgz#8f06caa12d0595a0538560abe771966d77d29286"
- integrity sha512-pGgnuxVddKcYIc+VJkRDop7gxLhqclNKBdlsm/5Vp8d+37pQkkDK7fef8d9YYImRzw9xcojEPc18pUYnbxmjqA==
- dependencies:
- "@types/babel-types" "*"
-
-"@types/babel-traverse@^6.25.2", "@types/babel-traverse@^6.25.3":
- version "6.25.5"
- resolved "https://registry.yarnpkg.com/@types/babel-traverse/-/babel-traverse-6.25.5.tgz#6d293cf7523e48b524faa7b86dc3c488191484e5"
- integrity sha512-WrMbwmu+MWf8FiUMbmVOGkc7bHPzndUafn1CivMaBHthBBoo0VNIcYk1KV71UovYguhsNOwf3UF5oRmkkGOU3w==
- dependencies:
- "@types/babel-types" "*"
-
-"@types/babel-types@*":
- version "7.0.9"
- resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41"
- integrity sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA==
-
-"@types/babel-types@^6.25.1":
- version "6.25.2"
- resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-6.25.2.tgz#5c57f45973e4f13742dbc5273dd84cffe7373a9e"
- integrity sha512-+3bMuktcY4a70a0KZc8aPJlEOArPuAKQYHU5ErjkOqGJdx8xuEEVK6nWogqigBOJ8nKPxRpyCUDTCPmZ3bUxGA==
-
-"@types/babylon@^6.16.2":
- version "6.16.5"
- resolved "https://registry.yarnpkg.com/@types/babylon/-/babylon-6.16.5.tgz#1c5641db69eb8cdf378edd25b4be7754beeb48b4"
- integrity sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==
- dependencies:
- "@types/babel-types" "*"
-
-"@types/bluebird@*":
- version "3.5.33"
- resolved "https://registry.yarnpkg.com/@types/bluebird/-/bluebird-3.5.33.tgz#d79c020f283bd50bd76101d7d300313c107325fc"
- integrity sha512-ndEo1xvnYeHxm7I/5sF6tBvnsA4Tdi3zj1keRKRs12SP+2ye2A27NDJ1B6PqkfMbGAcT+mqQVqbZRIrhfOp5PQ==
-
-"@types/body-parser@*":
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
- integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==
- dependencies:
- "@types/connect" "*"
- "@types/node" "*"
-
-"@types/cacheable-request@^6.0.1":
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.1.tgz#5d22f3dded1fd3a84c0bbeb5039a7419c2c91976"
- integrity sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==
- dependencies:
- "@types/http-cache-semantics" "*"
- "@types/keyv" "*"
- "@types/node" "*"
- "@types/responselike" "*"
-
-"@types/chai-subset@^1.3.0":
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
- integrity sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==
- dependencies:
- "@types/chai" "*"
-
-"@types/chai@*":
- version "4.2.16"
- resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.16.tgz#f09cc36e18d28274f942e7201147cce34d97e8c8"
- integrity sha512-vI5iOAsez9+roLS3M3+Xx7w+WRuDtSmF8bQkrbcIJ2sC1PcDgVoA0WGpa+bIrJ+y8zqY2oi//fUctkxtIcXJCw==
-
-"@types/chalk@^0.4.30":
- version "0.4.31"
- resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-0.4.31.tgz#a31d74241a6b1edbb973cf36d97a2896834a51f9"
- integrity sha1-ox10JBprHtu5c8822XooloNKUfk=
-
-"@types/chalk@^2.2.0":
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba"
- integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==
- dependencies:
- chalk "*"
-
-"@types/clean-css@*":
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.4.tgz#4fe4705c384e6ec9ee8454bc3d49089f38dc038a"
- integrity sha512-x8xEbfTtcv5uyQDrBXKg9Beo5QhTPqO4vM0uq4iU27/nhyRRWNEMKHjxvAb0WDvp2Mnt4Sw0jKmIi5yQF/k2Ag==
- dependencies:
- "@types/node" "*"
- source-map "^0.6.0"
-
-"@types/clone@^0.1.30":
- version "0.1.30"
- resolved "https://registry.yarnpkg.com/@types/clone/-/clone-0.1.30.tgz#e7365648c1b42136a59c7d5040637b3b5c83b614"
- integrity sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=
-
-"@types/compression@^0.0.33":
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/@types/compression/-/compression-0.0.33.tgz#95dc733a2339aa846381d7f1377792d2553dc27d"
- integrity sha1-ldxzOiM5qoRjgdfxN3eS0lU9wn0=
- dependencies:
- "@types/express" "*"
-
-"@types/connect@*":
- version "3.4.34"
- resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.34.tgz#170a40223a6d666006d93ca128af2beb1d9b1901"
- integrity sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==
- dependencies:
- "@types/node" "*"
-
-"@types/content-type@^1.1.0":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@types/content-type/-/content-type-1.1.3.tgz#3688bd77fc12f935548eef102a4e34c512b03a07"
- integrity sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==
-
-"@types/cssbeautify@^0.3.1":
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/@types/cssbeautify/-/cssbeautify-0.3.1.tgz#8e0bee8f7decb952250da0caebe05e30591c17ef"
- integrity sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=
-
-"@types/del@^3.0.0":
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/@types/del/-/del-3.0.1.tgz#4712da8c119873cbbf533ad8dbf1baac5940ac5d"
- integrity sha512-y6qRq6raBuu965clKgx6FHuiPu3oHdtmzMPXi8Uahsjdq1L6DL5fS/aY5/s71YwM7k6K1QIWvem5vNwlnNGIkQ==
- dependencies:
- "@types/glob" "*"
-
-"@types/doctrine@^0.0.1":
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/@types/doctrine/-/doctrine-0.0.1.tgz#b999f2d9f7b43cabe0a1a2f39bc203bc7dcada9d"
- integrity sha1-uZny2fe0PKvgoaLzm8IDvH3K2p0=
-
-"@types/escape-html@0.0.20":
- version "0.0.20"
- resolved "https://registry.yarnpkg.com/@types/escape-html/-/escape-html-0.0.20.tgz#cae698714dd61ebee5ab3f2aeb9a34ba1011735a"
- integrity sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==
-
-"@types/estree@*":
- version "0.0.47"
- resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
- integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==
-
-"@types/events@*":
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
- integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
-
-"@types/expect@^1.20.4":
- version "1.20.4"
- resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5"
- integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==
-
-"@types/express-serve-static-core@^4.17.18":
- version "4.17.19"
- resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz#00acfc1632e729acac4f1530e9e16f6dd1508a1d"
- integrity sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==
- dependencies:
- "@types/node" "*"
- "@types/qs" "*"
- "@types/range-parser" "*"
-
-"@types/express@*", "@types/express@^4.0.30", "@types/express@^4.0.36":
- version "4.17.11"
- resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.11.tgz#debe3caa6f8e5fcda96b47bd54e2f40c4ee59545"
- integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==
- dependencies:
- "@types/body-parser" "*"
- "@types/express-serve-static-core" "^4.17.18"
- "@types/qs" "*"
- "@types/serve-static" "*"
-
-"@types/fast-levenshtein@0.0.1":
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/@types/fast-levenshtein/-/fast-levenshtein-0.0.1.tgz#3a3615cf173645c8fca58d051e4e32824e4bd286"
- integrity sha1-OjYVzxc2Rcj8pY0FHk4ygk5L0oY=
-
-"@types/findup-sync@^0.3.29":
- version "0.3.30"
- resolved "https://registry.yarnpkg.com/@types/findup-sync/-/findup-sync-0.3.30.tgz#8ab7bdbd6ba7cbf4f33b6596fde6fff1129c738d"
- integrity sha512-Dpt1x3rhz6t8BMTS4vziTVos8VLkF4RngIxMBCSE6w0STmnVEEaoe3w+BG5xHyZXshye9lyZE99lpBDoLGY8eA==
- dependencies:
- "@types/minimatch" "*"
-
-"@types/form-data@*":
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.5.0.tgz#5025f7433016f923348434c40006d9a797c1b0e8"
- integrity sha512-23/wYiuckYYtFpL+4RPWiWmRQH2BjFuqCUi2+N3amB1a1Drv+i/byTrGvlLwRVLFNAZbwpbQ7JvTK+VCAPMbcg==
- dependencies:
- form-data "*"
-
-"@types/freeport@^1.0.19":
- version "1.0.21"
- resolved "https://registry.yarnpkg.com/@types/freeport/-/freeport-1.0.21.tgz#73f6543ed67d3ca3fff97b985591598b7092066f"
- integrity sha1-c/ZUPtZ9PKP/+XuYVZFZi3CSBm8=
-
-"@types/glob-stream@*":
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/@types/glob-stream/-/glob-stream-6.1.0.tgz#7ede8a33e59140534f8d8adfb8ac9edfb31897bc"
- integrity sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==
- dependencies:
- "@types/glob" "*"
- "@types/node" "*"
-
-"@types/glob@*", "@types/glob@^7.1.1":
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
- integrity sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==
- dependencies:
- "@types/minimatch" "*"
- "@types/node" "*"
-
-"@types/globby@^6.1.0":
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/@types/globby/-/globby-6.1.0.tgz#7c25b975512a89effea2a656ca8cf6db7fb29d11"
- integrity sha512-j3XSDNoK4LO5T+ZviQD6PqfEjm07QFEacOTbJR3hnLWuWX0ZMLJl9oRPgj1PyrfGbXhfHFkksC9QZ9HFltJyrw==
- dependencies:
- "@types/glob" "*"
-
-"@types/gulp-if@0.0.33":
- version "0.0.33"
- resolved "https://registry.yarnpkg.com/@types/gulp-if/-/gulp-if-0.0.33.tgz#edece22b7925d9a6db5f9c8c0d7882aa776fb678"
- integrity sha512-J5lzff21X7r1x/4hSzn02GgIUEyjCqYIXZ9GgGBLhbsD3RiBdqwnkFWgF16/0jO5rcVZ52Zp+6MQMQdvIsWuKg==
- dependencies:
- "@types/node" "*"
- "@types/vinyl" "*"
-
-"@types/html-minifier@^3.5.1":
- version "3.5.3"
- resolved "https://registry.yarnpkg.com/@types/html-minifier/-/html-minifier-3.5.3.tgz#5276845138db2cebc54c789e0aaf87621a21e84f"
- integrity sha512-j1P/4PcWVVCPEy5lofcHnQ6BtXz9tHGiFPWzqm7TtGuWZEfCHEP446HlkSNc9fQgNJaJZ6ewPtp2aaFla/Uerg==
- dependencies:
- "@types/clean-css" "*"
- "@types/relateurl" "*"
- "@types/uglify-js" "*"
-
-"@types/http-cache-semantics@*":
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz#9140779736aa2655635ee756e2467d787cfe8a2a"
- integrity sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==
-
-"@types/inquirer@*":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-7.3.1.tgz#1f231224e7df11ccfaf4cf9acbcc3b935fea292d"
- integrity sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==
- dependencies:
- "@types/through" "*"
- rxjs "^6.4.0"
-
-"@types/inquirer@0.0.32":
- version "0.0.32"
- resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.32.tgz#a4a08e83741c500a7c3c8e7776014f7f8a65870d"
- integrity sha1-pKCOg3QcUAp8PI53dgFPf4plhw0=
- dependencies:
- "@types/rx" "*"
- "@types/through" "*"
-
-"@types/is-windows@^0.2.0":
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-0.2.0.tgz#6f24ee48731d31168ea510610d6dd15e5fc9c6ff"
- integrity sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=
-
-"@types/json-schema@^7.0.3":
- version "7.0.7"
- resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz"
- integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
-
"@types/json-schema@^7.0.7":
version "7.0.9"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
@@ -1045,587 +172,121 @@
"@types/json5@^0.0.29":
version "0.0.29"
- resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz"
+ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
-"@types/keyv@*":
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.1.tgz#e45a45324fca9dab716ab1230ee249c9fb52cfa7"
- integrity sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==
- dependencies:
- "@types/node" "*"
-
-"@types/launchpad@^0.6.0":
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/@types/launchpad/-/launchpad-0.6.0.tgz#37296109b7f277f6e6c5fd7e0c0706bc918fbb51"
- integrity sha1-NylhCbfyd/bmxf1+DAcGvJGPu1E=
-
"@types/long@^4.0.0":
version "4.0.1"
- resolved "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9"
integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==
-"@types/merge-stream@^1.0.28":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@types/merge-stream/-/merge-stream-1.1.2.tgz#a880ff66b1fbbb5eef4958d015c5947a9334dbb1"
- integrity sha512-7faLmaE99g/yX0Y9pF1neh2IUqOf/fXMOWCVzsXjqI1EJ91lrgXmaBKf6bRWM164lLyiHxHt6t/ZO/cIzq61XA==
- dependencies:
- "@types/node" "*"
-
-"@types/mime@^1":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
- integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==
-
-"@types/mime@^2.0.0":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
- integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==
-
-"@types/minimatch@*", "@types/minimatch@^3.0.1", "@types/minimatch@^3.0.3":
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.4.tgz#f0ec25dbf2f0e4b18647313ac031134ca5b24b21"
- integrity sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==
-
"@types/minimatch@3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
"@types/minimist@^1.2.0":
- version "1.2.1"
- resolved "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz"
- integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
+ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
-"@types/mz@0.0.29":
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.29.tgz#bc24728c649973f1c7851e9033f9ce525668c27b"
- integrity sha1-vCRyjGSZc/HHhR6QM/nOUlZowns=
- dependencies:
- "@types/bluebird" "*"
- "@types/node" "*"
-
-"@types/mz@0.0.31", "@types/mz@^0.0.31":
- version "0.0.31"
- resolved "https://registry.yarnpkg.com/@types/mz/-/mz-0.0.31.tgz#a4d80c082fefe71e40a7c0f07d1e6555bbbc7b52"
- integrity sha1-pNgMCC/v5x5Ap8DwfR5lVbu8e1I=
- dependencies:
- "@types/node" "*"
-
-"@types/node@*", "@types/node@>= 8":
- version "14.14.37"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.37.tgz#a3dd8da4eb84a996c36e331df98d82abd76b516e"
- integrity sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==
+"@types/node@*":
+ version "16.9.6"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.6.tgz#040a64d7faf9e5d9e940357125f0963012e66f04"
+ integrity sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==
"@types/node@^10.1.0":
- version "10.17.56"
- resolved "https://registry.npmjs.org/@types/node/-/node-10.17.56.tgz"
- integrity sha512-LuAa6t1t0Bfw4CuSR0UITsm1hP17YL+u82kfHGrHUWdhlBtH7sa7jGY5z7glGaIj/WDYDkRtgGd+KCjCzxBW1w==
-
-"@types/node@^4.0.30":
- version "4.9.5"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-4.9.5.tgz#a3785db96b07a4b56466cc99fd624838746f2e25"
- integrity sha512-+8fpgbXsbATKRF2ayAlYhPl2E9MPdLjrnK/79ZEpyPJ+k7dZwJm9YM8FK+l4rqL//xHk7PgQhGwz6aA2ckxbCQ==
+ version "10.17.60"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b"
+ integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==
"@types/normalize-package-data@^2.4.0":
- version "2.4.0"
- resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
- integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
+ integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
-"@types/opn@^3.0.28":
- version "3.0.28"
- resolved "https://registry.yarnpkg.com/@types/opn/-/opn-3.0.28.tgz#097d0d1c9b5749573a5d96df132387bb6d02118a"
- integrity sha1-CX0NHJtXSVc6XZbfEyOHu20CEYo=
+"@typescript-eslint/eslint-plugin@^4.2.0", "@typescript-eslint/eslint-plugin@^4.29.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.30.0.tgz#4a0c1ae96b953f4e67435e20248d812bfa55e4fb"
+ integrity sha512-NgAnqk55RQ/SD+tZFD9aPwNSeHmDHHe5rtUyhIq0ZeCWZEvo4DK9rYz7v9HDuQZFvn320Ot+AikaCKMFKLlD0g==
dependencies:
- "@types/node" "*"
-
-"@types/parse5@^2.2.34":
- version "2.2.34"
- resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-2.2.34.tgz#e3870a10e82735a720f62d71dcd183ba78ef3a9d"
- integrity sha1-44cKEOgnNacg9i1x3NGDunjvOp0=
- dependencies:
- "@types/node" "*"
-
-"@types/path-is-inside@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/path-is-inside/-/path-is-inside-1.0.0.tgz#02d6ff38975d684bdec96204494baf9f29f0e17f"
- integrity sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==
-
-"@types/pem@^1.8.1":
- version "1.9.5"
- resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
- integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
- dependencies:
- "@types/node" "*"
-
-"@types/qs@*":
- version "6.9.6"
- resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.6.tgz#df9c3c8b31a247ec315e6996566be3171df4b3b1"
- integrity sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==
-
-"@types/range-parser@*":
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
- integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
-
-"@types/relateurl@*":
- version "0.2.28"
- resolved "https://registry.yarnpkg.com/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
- integrity sha1-a9p9uGU/piZD9e5p6facEaOS46Y=
-
-"@types/request@2.0.3":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/request/-/request-2.0.3.tgz#bdf0fba9488c822f77e97de3dd8fe357b2fb8c06"
- integrity sha512-cIvnyFRARxwE4OHpCyYue7H+SxaKFPpeleRCHJicft8QhyTNbVYsMwjvEzEPqG06D2LGHZ+sN5lXc8+bTu6D8A==
- dependencies:
- "@types/form-data" "*"
- "@types/node" "*"
-
-"@types/resolve@0.0.4":
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.4.tgz#9b586d65a947dea88c4bc24da0b905fe9520a0d5"
- integrity sha1-m1htZalH3qiMS8JNoLkF/pUgoNU=
- dependencies:
- "@types/node" "*"
-
-"@types/resolve@0.0.6":
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.6.tgz#0bd2f236c2e1cebb98b79885df57edd71a8d770e"
- integrity sha512-g+Rg8uMWY76oYTyaL+m7ZcblqF/oj7pE6uEUyACluJx4zcop1Lk14qQiocdEkEVMDFm6DmKpxJhsER+ZuTwG3g==
- dependencies:
- "@types/node" "*"
-
-"@types/resolve@0.0.7":
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.7.tgz#b299c13be8d712b1b502fb14a084252acef84f4d"
- integrity sha512-GPewdjkb0Q76o459qgp6pBLzJj/bD3oveS2kfLhIkZ9U3t3AFKtl5DlFB6lGTw0iZmcmxoGC8lpLW3NNJKrN9A==
- dependencies:
- "@types/node" "*"
-
-"@types/responselike@*", "@types/responselike@^1.0.0":
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
- integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
- dependencies:
- "@types/node" "*"
-
-"@types/rimraf@^0.0.28":
- version "0.0.28"
- resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-0.0.28.tgz#5562519bc7963caca8abf7f128cae3b594d41d06"
- integrity sha1-VWJRm8eWPKyoq/fxKMrjtZTUHQY=
-
-"@types/rx-core-binding@*":
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3"
- integrity sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==
- dependencies:
- "@types/rx-core" "*"
-
-"@types/rx-core@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-core/-/rx-core-4.0.3.tgz#0b3354b1238cedbe2b74f6326f139dbc7a591d60"
- integrity sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=
-
-"@types/rx-lite-aggregates@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz#6efb2b7f3d5f07183a1cb2bd4b1371d7073384c2"
- integrity sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-async@*":
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz#27fbf0caeff029f41e2d2aae638b05e91ceb600c"
- integrity sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-backpressure@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz#05abb19bdf87cc740196c355e5d0b37bb50b5d56"
- integrity sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-coincidence@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz#80bd69acc4054a15cdc1638e2dc8843498cd85c0"
- integrity sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-experimental@*":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz#c532f5cbdf3f2c15da16ded8930d1b2984023cbd"
- integrity sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-joinpatterns@*":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz#f70fe370518a8432f29158cc92ffb56b4e4afc3e"
- integrity sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-testing@*":
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz#21b19d11f4dfd6ffef5a9d1648e9c8879bfe21e9"
- integrity sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=
- dependencies:
- "@types/rx-lite-virtualtime" "*"
-
-"@types/rx-lite-time@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz#0eda65474570237598f3448b845d2696f2dbb1c4"
- integrity sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite-virtualtime@*":
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz#4b30cacd0fe2e53af29f04f7438584c7d3959537"
- integrity sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==
- dependencies:
- "@types/rx-lite" "*"
-
-"@types/rx-lite@*":
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/@types/rx-lite/-/rx-lite-4.0.6.tgz#3c02921c4244074234f26b772241bcc20c18c253"
- integrity sha512-oYiDrFIcor9zDm0VDUca1UbROiMYBxMLMaM6qzz4ADAfOmA9r1dYEcAFH+2fsPI5BCCjPvV9pWC3X3flbrvs7w==
- dependencies:
- "@types/rx-core" "*"
- "@types/rx-core-binding" "*"
-
-"@types/rx@*":
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.2.tgz#a4061b3d72b03cf11a38d69e2022a17334c54dc0"
- integrity sha512-1r8ZaT26Nigq7o4UBGl+aXB2UMFUIdLPP/8bLIP0x3d0pZL46ybKKjhWKaJQWIkLl5QCLD0nK3qTOO1QkwdFaA==
- dependencies:
- "@types/rx-core" "*"
- "@types/rx-core-binding" "*"
- "@types/rx-lite" "*"
- "@types/rx-lite-aggregates" "*"
- "@types/rx-lite-async" "*"
- "@types/rx-lite-backpressure" "*"
- "@types/rx-lite-coincidence" "*"
- "@types/rx-lite-experimental" "*"
- "@types/rx-lite-joinpatterns" "*"
- "@types/rx-lite-testing" "*"
- "@types/rx-lite-time" "*"
- "@types/rx-lite-virtualtime" "*"
-
-"@types/semver@^5.3.30":
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45"
- integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
-
-"@types/serve-static@*", "@types/serve-static@^1.7.31":
- version "1.13.9"
- resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.9.tgz#aacf28a85a05ee29a11fb7c3ead935ac56f33e4e"
- integrity sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==
- dependencies:
- "@types/mime" "^1"
- "@types/node" "*"
-
-"@types/spdy@^3.4.1":
- version "3.4.4"
- resolved "https://registry.yarnpkg.com/@types/spdy/-/spdy-3.4.4.tgz#3282fd4ad8c4603aa49f7017dd520a08a345b2bc"
- integrity sha512-N9LBlbVRRYq6HgYpPkqQc3a9HJ/iEtVZToW6xlTtJiMhmRJ7jJdV7TaZQJw/Ve/1ePUsQiCTDc4JMuzzag94GA==
- dependencies:
- "@types/node" "*"
-
-"@types/temp@^0.8.28":
- version "0.8.34"
- resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.8.34.tgz#03e4b3cb67cbb48c425bbf54b12230fef85540ac"
- integrity sha512-oLa9c5LHXgS6UimpEVp08De7QvZ+Dfu5bMQuWyMhf92Z26Q10ubEMOWy9OEfUdzW7Y/sDWVHmUaLFtmnX/2j0w==
- dependencies:
- "@types/node" "*"
-
-"@types/through@*":
- version "0.0.30"
- resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.30.tgz#e0e42ce77e897bd6aead6f6ea62aeb135b8a3895"
- integrity sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==
- dependencies:
- "@types/node" "*"
-
-"@types/ua-parser-js@^0.7.31":
- version "0.7.35"
- resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.35.tgz#cca67a95deb9165e4b1f449471801e6489d3fe93"
- integrity sha512-PsPx0RLbo2Un8+ff2buzYJnZjzwhD3jQHPOG2PtVIeOhkRDddMcKU8vJtHpzzfLB95dkUi0qAkfLg2l2Fd0yrQ==
-
-"@types/uglify-js@*":
- version "3.13.0"
- resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.13.0.tgz#1cad8df1fb0b143c5aba08de5712ea9d1ff71124"
- integrity sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==
- dependencies:
- source-map "^0.6.1"
-
-"@types/update-notifier@^1.0.0":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@types/update-notifier/-/update-notifier-1.0.3.tgz#3c7ee1921af6f16149cdcaef356baf57d7a0b806"
- integrity sha512-BLStNhP2DFF7funARwTcoD6tetRte8NK3Sc59mn7GNALCN975jOlKX3dGvsFxXr/HwQMxxCuRn9IWB3WQ7odHQ==
-
-"@types/uuid@^3.4.3":
- version "3.4.9"
- resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-3.4.9.tgz#fcf01997bbc9f7c09ae5f91383af076d466594e1"
- integrity sha512-XDwyIlt/47l2kWLTzw/mtrpLdB+GPSskR2n/PIcPn+VYhVO77rGhRncIR5GPU0KRzXuqkDO+J5qqrG0Y8P6jzQ==
-
-"@types/vinyl-fs@0.0.28":
- version "0.0.28"
- resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-0.0.28.tgz#4663017bc802c6570eae4f3409fd5cabf97cbfde"
- integrity sha1-RmMBe8gCxlcOrk80Cf1cq/l8v94=
- dependencies:
- "@types/glob-stream" "*"
- "@types/node" "*"
- "@types/vinyl" "*"
-
-"@types/vinyl-fs@^2.4.8":
- version "2.4.11"
- resolved "https://registry.yarnpkg.com/@types/vinyl-fs/-/vinyl-fs-2.4.11.tgz#b98119b8bb2494141eaf649b09fbfeb311161206"
- integrity sha512-2OzQSfIr9CqqWMGqmcERE6Hnd2KY3eBVtFaulVo3sJghplUcaeMdL9ZjEiljcQQeHjheWY9RlNmumjIAvsBNaA==
- dependencies:
- "@types/glob-stream" "*"
- "@types/node" "*"
- "@types/vinyl" "*"
-
-"@types/vinyl@*", "@types/vinyl@^2.0.0":
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/@types/vinyl/-/vinyl-2.0.4.tgz#9a7a8071c8d14d3a95d41ebe7135babe4ad5995a"
- integrity sha512-2o6a2ixaVI2EbwBPg1QYLGQoHK56p/8X/sGfKbFC8N6sY9lfjsMf/GprtkQkSya0D4uRiutRZ2BWj7k3JvLsAQ==
- dependencies:
- "@types/expect" "^1.20.4"
- "@types/node" "*"
-
-"@types/whatwg-url@^6.4.0":
- version "6.4.0"
- resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-6.4.0.tgz#1e59b8c64bc0dbdf66d037cf8449d1c3d5270237"
- integrity sha512-tonhlcbQ2eho09am6RHnHOgvtDfDYINd5rgxD+2YSkKENooVCFsWizJz139MQW/PV8FfClyKrNe9ZbdHrSCxGg==
- dependencies:
- "@types/node" "*"
-
-"@types/which@^1.3.1":
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
- integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA==
-
-"@types/yeoman-generator@^2.0.3":
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/@types/yeoman-generator/-/yeoman-generator-2.0.3.tgz#f4b161ee354078b526e0901a5a5f87d4f8e085f6"
- integrity sha512-vch2UFd6k7DdfWEv/alRwZIRXQoxZNUDpfLOK24+005dzE1HVnwSWfETF3WxJnWlsOcH87wU4uzldAE/7F/6Lw==
- dependencies:
- "@types/events" "*"
- "@types/inquirer" "*"
-
-"@typescript-eslint/eslint-plugin@^4.2.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.21.0.tgz"
- integrity sha512-FPUyCPKZbVGexmbCFI3EQHzCZdy2/5f+jv6k2EDljGdXSRc0cKvbndd2nHZkSLqCNOPk0jB6lGzwIkglXcYVsQ==
- dependencies:
- "@typescript-eslint/experimental-utils" "4.21.0"
- "@typescript-eslint/scope-manager" "4.21.0"
- debug "^4.1.1"
- functional-red-black-tree "^1.0.1"
- lodash "^4.17.15"
- regexpp "^3.0.0"
- semver "^7.3.2"
- tsutils "^3.17.1"
-
-"@typescript-eslint/eslint-plugin@^4.25.0":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d"
- integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg==
- dependencies:
- "@typescript-eslint/experimental-utils" "4.29.2"
- "@typescript-eslint/scope-manager" "4.29.2"
+ "@typescript-eslint/experimental-utils" "4.30.0"
+ "@typescript-eslint/scope-manager" "4.30.0"
debug "^4.3.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.1.0"
semver "^7.3.5"
tsutils "^3.21.0"
-"@typescript-eslint/experimental-utils@4.21.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.21.0.tgz"
- integrity sha512-cEbgosW/tUFvKmkg3cU7LBoZhvUs+ZPVM9alb25XvR0dal4qHL3SiUqHNrzoWSxaXA9gsifrYrS1xdDV6w/gIA==
- dependencies:
- "@types/json-schema" "^7.0.3"
- "@typescript-eslint/scope-manager" "4.21.0"
- "@typescript-eslint/types" "4.21.0"
- "@typescript-eslint/typescript-estree" "4.21.0"
- eslint-scope "^5.0.0"
- eslint-utils "^2.0.0"
-
-"@typescript-eslint/experimental-utils@4.29.2":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7"
- integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A==
+"@typescript-eslint/experimental-utils@4.30.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.30.0.tgz#9e49704fef568432ae16fc0d6685c13d67db0fd5"
+ integrity sha512-K8RNIX9GnBsv5v4TjtwkKtqMSzYpjqAQg/oSphtxf3xxdt6T0owqnpojztjjTcatSteH3hLj3t/kklKx87NPqw==
dependencies:
"@types/json-schema" "^7.0.7"
- "@typescript-eslint/scope-manager" "4.29.2"
- "@typescript-eslint/types" "4.29.2"
- "@typescript-eslint/typescript-estree" "4.29.2"
+ "@typescript-eslint/scope-manager" "4.30.0"
+ "@typescript-eslint/types" "4.30.0"
+ "@typescript-eslint/typescript-estree" "4.30.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/parser@^4.2.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.21.0.tgz"
- integrity sha512-eyNf7QmE5O/l1smaQgN0Lj2M/1jOuNg2NrBm1dqqQN0sVngTLyw8tdCbih96ixlhbF1oINoN8fDCyEH9SjLeIA==
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.30.0.tgz#6abd720f66bd790f3e0e80c3be77180c8fcb192d"
+ integrity sha512-HJ0XuluSZSxeboLU7Q2VQ6eLlCwXPBOGnA7CqgBnz2Db3JRQYyBDJgQnop6TZ+rsbSx5gEdWhw4rE4mDa1FnZg==
dependencies:
- "@typescript-eslint/scope-manager" "4.21.0"
- "@typescript-eslint/types" "4.21.0"
- "@typescript-eslint/typescript-estree" "4.21.0"
- debug "^4.1.1"
+ "@typescript-eslint/scope-manager" "4.30.0"
+ "@typescript-eslint/types" "4.30.0"
+ "@typescript-eslint/typescript-estree" "4.30.0"
+ debug "^4.3.1"
-"@typescript-eslint/scope-manager@4.21.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.21.0.tgz"
- integrity sha512-kfOjF0w1Ix7+a5T1knOw00f7uAP9Gx44+OEsNQi0PvvTPLYeXJlsCJ4tYnDj5PQEYfpcgOH5yBlw7K+UEI9Agw==
+"@typescript-eslint/scope-manager@4.30.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.30.0.tgz#1a3ffbb385b1a06be85cd5165a22324f069a85ee"
+ integrity sha512-VJ/jAXovxNh7rIXCQbYhkyV2Y3Ac/0cVHP/FruTJSAUUm4Oacmn/nkN5zfWmWFEanN4ggP0vJSHOeajtHq3f8A==
dependencies:
- "@typescript-eslint/types" "4.21.0"
- "@typescript-eslint/visitor-keys" "4.21.0"
+ "@typescript-eslint/types" "4.30.0"
+ "@typescript-eslint/visitor-keys" "4.30.0"
-"@typescript-eslint/scope-manager@4.29.2":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b"
- integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA==
+"@typescript-eslint/types@4.30.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.30.0.tgz#fb9d9b0358426f18687fba82eb0b0f869780204f"
+ integrity sha512-YKldqbNU9K4WpTNwBqtAerQKLLW/X2A/j4yw92e3ZJYLx+BpKLeheyzoPfzIXHfM8BXfoleTdiYwpsvVPvHrDw==
+
+"@typescript-eslint/typescript-estree@4.30.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.30.0.tgz#ae57833da72a753f4846cd3053758c771670c2ac"
+ integrity sha512-6WN7UFYvykr/U0Qgy4kz48iGPWILvYL34xXJxvDQeiRE018B7POspNRVtAZscWntEPZpFCx4hcz/XBT+erenfg==
dependencies:
- "@typescript-eslint/types" "4.29.2"
- "@typescript-eslint/visitor-keys" "4.29.2"
-
-"@typescript-eslint/types@4.21.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.21.0.tgz"
- integrity sha512-+OQaupjGVVc8iXbt6M1oZMwyKQNehAfLYJJ3SdvnofK2qcjfor9pEM62rVjBknhowTkh+2HF+/KdRAc/wGBN2w==
-
-"@typescript-eslint/types@4.29.2":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd"
- integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ==
-
-"@typescript-eslint/typescript-estree@4.21.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.21.0.tgz"
- integrity sha512-ZD3M7yLaVGVYLw4nkkoGKumb7Rog7QID9YOWobFDMQKNl+vPxqVIW/uDk+MDeGc+OHcoG2nJ2HphwiPNajKw3w==
- dependencies:
- "@typescript-eslint/types" "4.21.0"
- "@typescript-eslint/visitor-keys" "4.21.0"
- debug "^4.1.1"
- globby "^11.0.1"
- is-glob "^4.0.1"
- semver "^7.3.2"
- tsutils "^3.17.1"
-
-"@typescript-eslint/typescript-estree@4.29.2":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219"
- integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg==
- dependencies:
- "@typescript-eslint/types" "4.29.2"
- "@typescript-eslint/visitor-keys" "4.29.2"
+ "@typescript-eslint/types" "4.30.0"
+ "@typescript-eslint/visitor-keys" "4.30.0"
debug "^4.3.1"
globby "^11.0.3"
is-glob "^4.0.1"
semver "^7.3.5"
tsutils "^3.21.0"
-"@typescript-eslint/visitor-keys@4.21.0":
- version "4.21.0"
- resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.21.0.tgz"
- integrity sha512-dH22dROWGi5Z6p+Igc8bLVLmwy7vEe8r+8c+raPQU0LxgogPUrRAtRGtvBWmlr9waTu3n+QLt/qrS/hWzk1x5w==
+"@typescript-eslint/visitor-keys@4.30.0":
+ version "4.30.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.30.0.tgz#a47c6272fc71b0c627d1691f68eaecf4ad71445e"
+ integrity sha512-pNaaxDt/Ol/+JZwzP7MqWc8PJQTUhZwoee/PVlQ+iYoYhagccvoHnC9e4l+C/krQYYkENxznhVSDwClIbZVxRw==
dependencies:
- "@typescript-eslint/types" "4.21.0"
+ "@typescript-eslint/types" "4.30.0"
eslint-visitor-keys "^2.0.0"
-"@typescript-eslint/visitor-keys@4.29.2":
- version "4.29.2"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df"
- integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag==
- dependencies:
- "@typescript-eslint/types" "4.29.2"
- eslint-visitor-keys "^2.0.0"
-
-"@webcomponents/webcomponentsjs@^1.0.7":
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.3.tgz#5bb82a0d3210c836bd4623e13a4a93145cb9dc27"
- integrity sha512-eLH04VBMpuZGzBIhOnUjECcQPEPcmfhWEijW9u1B5I+2PPYdWf3vWUExdDxu4Y3GljRSTCOlWnGtS9tpzmXMyQ==
-
-JSONStream@^1.2.1, JSONStream@^1.3.5:
- version "1.3.5"
- resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
- integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==
- dependencies:
- jsonparse "^1.2.0"
- through ">=2.2.7 <3"
-
-accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
- version "1.3.7"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
- integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
- dependencies:
- mime-types "~2.1.24"
- negotiator "0.6.2"
-
-accessibility-developer-tools@^2.12.0:
- version "2.12.0"
- resolved "https://registry.yarnpkg.com/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz#3da0cce9d6ec6373964b84f35db7cfc3df7ab514"
- integrity sha1-PaDM6dbsY3OWS4TzXbfPw996tRQ=
-
-acorn-jsx@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
- integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
- dependencies:
- acorn "^3.0.4"
-
acorn-jsx@^5.3.1:
- version "5.3.1"
- resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz"
- integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-acorn@^3.0.4:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
- integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
-
-acorn@^5.5.0:
- version "5.7.4"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
- integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
-
-acorn@^7.1.0, acorn@^7.4.0:
+acorn@^7.4.0:
version "7.4.1"
- resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
-adm-zip@~0.4.3:
- version "0.4.16"
- resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365"
- integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==
-
-after@0.8.2:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
- integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
-
-agent-base@6:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
- integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
- dependencies:
- debug "4"
-
-agent-base@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
- integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
- dependencies:
- es6-promisify "^5.0.0"
-
-ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
+ajv@^6.10.0, ajv@^6.12.4:
version "6.12.6"
- resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
dependencies:
fast-deep-equal "^3.1.1"
@@ -1634,208 +295,68 @@
uri-js "^4.2.2"
ajv@^8.0.1:
- version "8.0.5"
- resolved "https://registry.npmjs.org/ajv/-/ajv-8.0.5.tgz"
- integrity sha512-RkiLa/AeJx7+9OvniQ/qeWu0w74A8DiPPBclQ6ji3ZQkv5KamO+QGpqmi7O4JIw3rHGUXZ6CoP9tsAkn3gyazg==
+ version "8.6.2"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571"
+ integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
require-from-string "^2.0.2"
uri-js "^4.2.2"
-ansi-align@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-1.1.0.tgz#2f0c1658829739add5ebb15e6b0c6e3423f016ba"
- integrity sha1-LwwWWIKXOa3V67FeawxuNCPwFro=
- dependencies:
- string-width "^1.0.1"
-
-ansi-align@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
- integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
- dependencies:
- string-width "^2.0.0"
-
ansi-align@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
dependencies:
string-width "^3.0.0"
ansi-colors@^4.1.1:
version "4.1.1"
- resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
-ansi-escapes@^1.1.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
- integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
-
ansi-escapes@^4.2.1:
version "4.3.2"
- resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
dependencies:
type-fest "^0.21.3"
-ansi-regex@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
- integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ansi-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
- integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-
ansi-regex@^4.1.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
ansi-regex@^5.0.0:
version "5.0.0"
- resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-ansi-styles@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
- integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
-
ansi-styles@^3.2.1:
version "3.2.1"
- resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
dependencies:
color-convert "^1.9.0"
ansi-styles@^4.0.0, ansi-styles@^4.1.0:
version "4.3.0"
- resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
dependencies:
color-convert "^2.0.1"
-ansi-styles@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178"
- integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=
-
-any-promise@^1.0.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
- integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
-
-anymatch@^1.3.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.2.tgz#553dcb8f91e3c889845dfdba34c77721b90b9d7a"
- integrity sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==
- dependencies:
- micromatch "^2.1.5"
- normalize-path "^2.0.0"
-
-append-field@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
- integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
-
-archiver-utils@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
- integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
- dependencies:
- glob "^7.1.4"
- graceful-fs "^4.2.0"
- lazystream "^1.0.0"
- lodash.defaults "^4.2.0"
- lodash.difference "^4.5.0"
- lodash.flatten "^4.4.0"
- lodash.isplainobject "^4.0.6"
- lodash.union "^4.6.0"
- normalize-path "^3.0.0"
- readable-stream "^2.0.0"
-
-archiver@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/archiver/-/archiver-3.1.1.tgz#9db7819d4daf60aec10fe86b16cb9258ced66ea0"
- integrity sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==
- dependencies:
- archiver-utils "^2.1.0"
- async "^2.6.3"
- buffer-crc32 "^0.2.1"
- glob "^7.1.4"
- readable-stream "^3.4.0"
- tar-stream "^2.1.0"
- zip-stream "^2.1.2"
-
argparse@^1.0.7:
version "1.0.10"
- resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
dependencies:
sprintf-js "~1.0.2"
-arr-diff@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf"
- integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=
- dependencies:
- arr-flatten "^1.0.1"
-
-arr-diff@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
- integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
-
-arr-flatten@^1.0.1, arr-flatten@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
- integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
-
-arr-union@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
- integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
-
-array-back@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022"
- integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw==
- dependencies:
- typical "^2.6.1"
-
-array-back@^3.0.1:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
- integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
-
-array-differ@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031"
- integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=
-
-array-differ@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b"
- integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==
-
-array-find-index@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
- integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
-
-array-flatten@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
- integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
-
-array-includes@^3.1.1:
+array-includes@^3.1.3:
version "3.1.3"
- resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a"
integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==
dependencies:
call-bind "^1.0.2"
@@ -1844,597 +365,43 @@
get-intrinsic "^1.1.1"
is-string "^1.0.5"
-array-union@^1.0.1, array-union@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
- integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
- dependencies:
- array-uniq "^1.0.1"
-
array-union@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-array-uniq@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
- integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
-
-array-unique@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
- integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=
-
-array-unique@^0.3.2:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
- integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
-
-array.prototype.flat@^1.2.3:
+array.prototype.flat@^1.2.4:
version "1.2.4"
- resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123"
integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==
dependencies:
call-bind "^1.0.0"
define-properties "^1.1.3"
es-abstract "^1.18.0-next.1"
-arraybuffer.slice@~0.0.7:
- version "0.0.7"
- resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
- integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==
-
-arrify@^1.0.0, arrify@^1.0.1:
+arrify@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
-arrify@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa"
- integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==
-
-asn1@~0.2.3:
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
- integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
- dependencies:
- safer-buffer "~2.1.0"
-
-assert-plus@1.0.0, assert-plus@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
- integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
-
-assign-symbols@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
- integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
-
astral-regex@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
-async-each@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
- integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
-
-async@0.9.x:
- version "0.9.2"
- resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
- integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
-
-async@^2.0.0, async@^2.0.1, async@^2.1.2, async@^2.4.1, async@^2.6.0, async@^2.6.2, async@^2.6.3:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
- integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
- dependencies:
- lodash "^4.17.14"
-
-async@^3.1.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
- integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
-
-async@~0.2.9:
- version "0.2.10"
- resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
- integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
-
-asynckit@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
- integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
-
-atob-lite@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696"
- integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY=
-
-atob@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
- integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
-
-aws-sign2@~0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
- integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
-
-aws4@^1.8.0:
- version "1.11.0"
- resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
- integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
-
-axios@^0.21.1:
- version "0.21.1"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
- integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
- dependencies:
- follow-redirects "^1.10.0"
-
-babel-code-frame@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
- integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
- dependencies:
- chalk "^1.1.3"
- esutils "^2.0.2"
- js-tokens "^3.0.2"
-
-babel-generator@^6.26.1:
- version "6.26.1"
- resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
- integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==
- dependencies:
- babel-messages "^6.23.0"
- babel-runtime "^6.26.0"
- babel-types "^6.26.0"
- detect-indent "^4.0.0"
- jsesc "^1.3.0"
- lodash "^4.17.4"
- source-map "^0.5.7"
- trim-right "^1.0.1"
-
-babel-helper-evaluate-path@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.5.0.tgz#a62fa9c4e64ff7ea5cea9353174ef023a900a67c"
- integrity sha512-mUh0UhS607bGh5wUMAQfOpt2JX2ThXMtppHRdRU1kL7ZLRWIXxoV2UIV1r2cAeeNeU1M5SB5/RSUgUxrK8yOkA==
-
-babel-helper-flip-expressions@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.4.3.tgz#3696736a128ac18bc25254b5f40a22ceb3c1d3fd"
- integrity sha1-NpZzahKKwYvCUlS19AoizrPB0/0=
-
-babel-helper-is-nodes-equiv@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
- integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=
-
-babel-helper-is-void-0@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.4.3.tgz#7d9c01b4561e7b95dbda0f6eee48f5b60e67313e"
- integrity sha1-fZwBtFYee5Xb2g9u7kj1tg5nMT4=
-
-babel-helper-mark-eval-scopes@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.4.3.tgz#d244a3bef9844872603ffb46e22ce8acdf551562"
- integrity sha1-0kSjvvmESHJgP/tG4izorN9VFWI=
-
-babel-helper-remove-or-void@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.4.3.tgz#a4f03b40077a0ffe88e45d07010dee241ff5ae60"
- integrity sha1-pPA7QAd6D/6I5F0HAQ3uJB/1rmA=
-
-babel-helper-to-multiple-sequence-expressions@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.5.0.tgz#a3f924e3561882d42fcf48907aa98f7979a4588d"
- integrity sha512-m2CvfDW4+1qfDdsrtf4dwOslQC3yhbgyBFptncp4wvtdrDHqueW7slsYv4gArie056phvQFhT2nRcGS4bnm6mA==
-
-babel-messages@^6.23.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
- integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
- dependencies:
- babel-runtime "^6.22.0"
-
-babel-plugin-dynamic-import-node@^2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3"
- integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==
- dependencies:
- object.assign "^4.1.0"
-
-babel-plugin-minify-builtins@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b"
- integrity sha512-wpqbN7Ov5hsNwGdzuzvFcjgRlzbIeVv1gMIlICbPj0xkexnfoIDe7q+AZHMkQmAE/F9R5jkrB6TLfTegImlXag==
-
-babel-plugin-minify-constant-folding@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.5.0.tgz#f84bc8dbf6a561e5e350ff95ae216b0ad5515b6e"
- integrity sha512-Vj97CTn/lE9hR1D+jKUeHfNy+m1baNiJ1wJvoGyOBUx7F7kJqDZxr9nCHjO/Ad+irbR3HzR6jABpSSA29QsrXQ==
- dependencies:
- babel-helper-evaluate-path "^0.5.0"
-
-babel-plugin-minify-dead-code-elimination@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.5.1.tgz#1a0c68e44be30de4976ca69ffc535e08be13683f"
- integrity sha512-x8OJOZIrRmQBcSqxBcLbMIK8uPmTvNWPXH2bh5MDCW1latEqYiRMuUkPImKcfpo59pTUB2FT7HfcgtG8ZlR5Qg==
- dependencies:
- babel-helper-evaluate-path "^0.5.0"
- babel-helper-mark-eval-scopes "^0.4.3"
- babel-helper-remove-or-void "^0.4.3"
- lodash "^4.17.11"
-
-babel-plugin-minify-flip-comparisons@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.4.3.tgz#00ca870cb8f13b45c038b3c1ebc0f227293c965a"
- integrity sha1-AMqHDLjxO0XAOLPB68DyJyk8llo=
- dependencies:
- babel-helper-is-void-0 "^0.4.3"
-
-babel-plugin-minify-guarded-expressions@^0.4.3, babel-plugin-minify-guarded-expressions@^0.4.4:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.4.4.tgz#818960f64cc08aee9d6c75bec6da974c4d621135"
- integrity sha512-RMv0tM72YuPPfLT9QLr3ix9nwUIq+sHT6z8Iu3sLbqldzC1Dls8DPCywzUIzkTx9Zh1hWX4q/m9BPoPed9GOfA==
- dependencies:
- babel-helper-evaluate-path "^0.5.0"
- babel-helper-flip-expressions "^0.4.3"
-
-babel-plugin-minify-infinity@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.4.3.tgz#dfb876a1b08a06576384ef3f92e653ba607b39ca"
- integrity sha1-37h2obCKBldjhO8/kuZTumB7Oco=
-
-babel-plugin-minify-mangle-names@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.5.0.tgz#bcddb507c91d2c99e138bd6b17a19c3c271e3fd3"
- integrity sha512-3jdNv6hCAw6fsX1p2wBGPfWuK69sfOjfd3zjUXkbq8McbohWy23tpXfy5RnToYWggvqzuMOwlId1PhyHOfgnGw==
- dependencies:
- babel-helper-mark-eval-scopes "^0.4.3"
-
-babel-plugin-minify-numeric-literals@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.4.3.tgz#8e4fd561c79f7801286ff60e8c5fd9deee93c0bc"
- integrity sha1-jk/VYcefeAEob/YOjF/Z3u6TwLw=
-
-babel-plugin-minify-replace@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.5.0.tgz#d3e2c9946c9096c070efc96761ce288ec5c3f71c"
- integrity sha512-aXZiaqWDNUbyNNNpWs/8NyST+oU7QTpK7J9zFEFSA0eOmtUNMU3fczlTTTlnCxHmq/jYNFEmkkSG3DDBtW3Y4Q==
-
-babel-plugin-minify-simplify@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.5.1.tgz#f21613c8b95af3450a2ca71502fdbd91793c8d6a"
- integrity sha512-OSYDSnoCxP2cYDMk9gxNAed6uJDiDz65zgL6h8d3tm8qXIagWGMLWhqysT6DY3Vs7Fgq7YUDcjOomhVUb+xX6A==
- dependencies:
- babel-helper-evaluate-path "^0.5.0"
- babel-helper-flip-expressions "^0.4.3"
- babel-helper-is-nodes-equiv "^0.0.1"
- babel-helper-to-multiple-sequence-expressions "^0.5.0"
-
-babel-plugin-minify-type-constructors@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.4.3.tgz#1bc6f15b87f7ab1085d42b330b717657a2156500"
- integrity sha1-G8bxW4f3qxCF1CszC3F2V6IVZQA=
- dependencies:
- babel-helper-is-void-0 "^0.4.3"
-
-babel-plugin-transform-inline-consecutive-adds@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.4.3.tgz#323d47a3ea63a83a7ac3c811ae8e6941faf2b0d1"
- integrity sha1-Mj1Ho+pjqDp6w8gRro5pQfrysNE=
-
-babel-plugin-transform-member-expression-literals@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf"
- integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=
-
-babel-plugin-transform-merge-sibling-variables@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae"
- integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=
-
-babel-plugin-transform-minify-booleans@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
- integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
-
-babel-plugin-transform-property-literals@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
- integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=
- dependencies:
- esutils "^2.0.2"
-
-babel-plugin-transform-regexp-constructors@^0.4.3:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.4.3.tgz#58b7775b63afcf33328fae9a5f88fbd4fb0b4965"
- integrity sha1-WLd3W2OvzzMyj66aX4j71PsLSWU=
-
-babel-plugin-transform-remove-console@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
- integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
-
-babel-plugin-transform-remove-debugger@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2"
- integrity sha1-QrcnYxyXl44estGZp67IShgznvI=
-
-babel-plugin-transform-remove-undefined@^0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.5.0.tgz#80208b31225766c630c97fa2d288952056ea22dd"
- integrity sha512-+M7fJYFaEE/M9CXa0/IRkDbiV3wRELzA1kKQFCJ4ifhrzLKn/9VCCgj9OFmYWwBd8IB48YdgPkHYtbYq+4vtHQ==
- dependencies:
- babel-helper-evaluate-path "^0.5.0"
-
-babel-plugin-transform-simplify-comparison-operators@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9"
- integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=
-
-babel-plugin-transform-undefined-to-void@^6.9.4:
- version "6.9.4"
- resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280"
- integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
-
-babel-preset-minify@^0.5.0:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.5.1.tgz#25f5d0bce36ec818be80338d0e594106e21eaa9f"
- integrity sha512-1IajDumYOAPYImkHbrKeiN5AKKP9iOmRoO2IPbIuVp0j2iuCcj0n7P260z38siKMZZ+85d3mJZdtW8IgOv+Tzg==
- dependencies:
- babel-plugin-minify-builtins "^0.5.0"
- babel-plugin-minify-constant-folding "^0.5.0"
- babel-plugin-minify-dead-code-elimination "^0.5.1"
- babel-plugin-minify-flip-comparisons "^0.4.3"
- babel-plugin-minify-guarded-expressions "^0.4.4"
- babel-plugin-minify-infinity "^0.4.3"
- babel-plugin-minify-mangle-names "^0.5.0"
- babel-plugin-minify-numeric-literals "^0.4.3"
- babel-plugin-minify-replace "^0.5.0"
- babel-plugin-minify-simplify "^0.5.1"
- babel-plugin-minify-type-constructors "^0.4.3"
- babel-plugin-transform-inline-consecutive-adds "^0.4.3"
- babel-plugin-transform-member-expression-literals "^6.9.4"
- babel-plugin-transform-merge-sibling-variables "^6.9.4"
- babel-plugin-transform-minify-booleans "^6.9.4"
- babel-plugin-transform-property-literals "^6.9.4"
- babel-plugin-transform-regexp-constructors "^0.4.3"
- babel-plugin-transform-remove-console "^6.9.4"
- babel-plugin-transform-remove-debugger "^6.9.4"
- babel-plugin-transform-remove-undefined "^0.5.0"
- babel-plugin-transform-simplify-comparison-operators "^6.9.4"
- babel-plugin-transform-undefined-to-void "^6.9.4"
- lodash "^4.17.11"
-
-babel-runtime@^6.22.0, babel-runtime@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
- integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
- dependencies:
- core-js "^2.4.0"
- regenerator-runtime "^0.11.0"
-
-babel-traverse@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
- integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
- dependencies:
- babel-code-frame "^6.26.0"
- babel-messages "^6.23.0"
- babel-runtime "^6.26.0"
- babel-types "^6.26.0"
- babylon "^6.18.0"
- debug "^2.6.8"
- globals "^9.18.0"
- invariant "^2.2.2"
- lodash "^4.17.4"
-
-babel-types@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
- integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
- dependencies:
- babel-runtime "^6.26.0"
- esutils "^2.0.2"
- lodash "^4.17.4"
- to-fast-properties "^1.0.3"
-
-babylon@^6.18.0:
- version "6.18.0"
- resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
- integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
-
-babylon@^7.0.0-beta.42:
- version "7.0.0-beta.47"
- resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.47.tgz#6d1fa44f0abec41ab7c780481e62fd9aafbdea80"
- integrity sha512-+rq2cr4GDhtToEzKFD6KZZMDBXhjFAr9JjPw9pAppZACeEWqNM294j+NdBzkSHYXwzzBmVjZ3nEVJlOhbR2gOQ==
-
-backo2@1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
- integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
-
balanced-match@^1.0.0:
version "1.0.2"
- resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-base64-arraybuffer@0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812"
- integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=
-
-base64-js@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
- integrity sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=
-
-base64-js@^1.3.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
- integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-
-base64id@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6"
- integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==
-
-base@^0.11.1:
- version "0.11.2"
- resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
- integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
- dependencies:
- cache-base "^1.0.1"
- class-utils "^0.3.5"
- component-emitter "^1.2.1"
- define-property "^1.0.0"
- isobject "^3.0.1"
- mixin-deep "^1.2.0"
- pascalcase "^0.1.1"
-
-bcrypt-pbkdf@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
- integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
- dependencies:
- tweetnacl "^0.14.3"
-
-before-after-hook@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.1.tgz#73540563558687586b52ed217dad6a802ab1549c"
- integrity sha512-/6FKxSTWoJdbsLDF8tdIjaRiFXiE6UHsEHE3OPI/cwPURCVi1ukP0gmLn7XWEiFk5TcwQjjY5PWsU+j+tgXgmw==
-
-binary-extensions@^1.0.0:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
- integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
-
-binaryextensions@^2.1.2:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.3.0.tgz#1d269cbf7e6243ea886aa41453c3651ccbe13c22"
- integrity sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg==
-
-bindings@^1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
- integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
- dependencies:
- file-uri-to-path "1.0.0"
-
-bl@^1.0.0:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7"
- integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==
- dependencies:
- readable-stream "^2.3.5"
- safe-buffer "^5.1.1"
-
-bl@^4.0.3:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
- integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
- dependencies:
- buffer "^5.5.0"
- inherits "^2.0.4"
- readable-stream "^3.4.0"
-
-blob@0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
- integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==
-
-body-parser@1.19.0, body-parser@^1.17.2:
- version "1.19.0"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
- integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
- dependencies:
- bytes "3.1.0"
- content-type "~1.0.4"
- debug "2.6.9"
- depd "~1.1.2"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- on-finished "~2.3.0"
- qs "6.7.0"
- raw-body "2.4.0"
- type-is "~1.6.17"
-
boolbase@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
-bower-config@^1.4.0, bower-config@^1.4.1:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.3.tgz#3454fecdc5f08e7aa9cc6d556e492be0669689ae"
- integrity sha512-MVyyUk3d1S7d2cl6YISViwJBc2VXCkxF5AUFykvN0PQj5FsUiMNSgAYTso18oRFfyZ6XEtjrgg9MAaufHbOwNw==
- dependencies:
- graceful-fs "^4.1.3"
- minimist "^0.2.1"
- mout "^1.0.0"
- osenv "^0.1.3"
- untildify "^2.1.0"
- wordwrap "^0.0.3"
-
-bower-json@^0.8.1:
- version "0.8.4"
- resolved "https://registry.yarnpkg.com/bower-json/-/bower-json-0.8.4.tgz#9c3b375870dcd9581350c1f403f6383dbf6a18b1"
- integrity sha512-mMKghvq9ivbuzSsY5nrOLnDtZIJMUCpysqbGaGW3mj88JAcuSi8ZAzIt34vNZjohy0aR9VXLwgPTZGnBX2Vpjg==
- dependencies:
- deep-extend "^0.5.1"
- ends-with "^0.2.0"
- ext-list "^2.0.0"
- graceful-fs "^4.1.3"
- intersect "^1.0.1"
- sort-keys-length "^1.0.0"
-
-bower-logger@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/bower-logger/-/bower-logger-0.2.2.tgz#39be07e979b2fc8e03a94634205ed9422373d381"
- integrity sha1-Ob4H6Xmy/I4DqUY0IF7ZQiNz04E=
-
-bower@^1.8.8:
- version "1.8.12"
- resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.12.tgz#44cfca2a5e04b8d9a066621e24c8b179d8ac321e"
- integrity sha512-u1xy9SrwwoPlgjuHNjhV+YUPVdqyBj2ALBxuzeIUKXaPI2i2xypGgxqXkuHcITGdi5yBj5JuXgyMvgiWiS1S3Q==
-
-boxen@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-0.6.0.tgz#8364d4248ac34ff0ef1b2f2bf49a6c60ce0d81b6"
- integrity sha1-g2TUJIrDT/DvGy8r9JpsYM4NgbY=
- dependencies:
- ansi-align "^1.1.0"
- camelcase "^2.1.0"
- chalk "^1.1.1"
- cli-boxes "^1.0.0"
- filled-array "^1.0.0"
- object-assign "^4.0.1"
- repeating "^2.0.0"
- string-width "^1.0.1"
- widest-line "^1.0.0"
-
-boxen@^1.2.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
- integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
- dependencies:
- ansi-align "^2.0.0"
- camelcase "^4.0.0"
- chalk "^2.0.1"
- cli-boxes "^1.0.0"
- string-width "^2.0.0"
- term-size "^1.2.0"
- widest-line "^2.0.0"
-
boxen@^5.0.0:
version "5.0.1"
- resolved "https://registry.npmjs.org/boxen/-/boxen-5.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.0.1.tgz#657528bdd3f59a772b8279b831f27ec2c744664b"
integrity sha512-49VBlw+PrWEF51aCmy7QIteYPIFZxSpvqBdP/2itCPPlJ49kj9zg/XPRFrdkne2W+CfwXUls8exMvu1RysZpKA==
dependencies:
ansi-align "^3.0.0"
@@ -2448,159 +415,27 @@
brace-expansion@^1.0.0, brace-expansion@^1.1.7:
version "1.1.11"
- resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
-braces@^1.8.2:
- version "1.8.5"
- resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
- integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=
- dependencies:
- expand-range "^1.8.1"
- preserve "^0.2.0"
- repeat-element "^1.1.2"
-
-braces@^2.3.1:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
- integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
- dependencies:
- arr-flatten "^1.1.0"
- array-unique "^0.3.2"
- extend-shallow "^2.0.1"
- fill-range "^4.0.0"
- isobject "^3.0.1"
- repeat-element "^1.1.2"
- snapdragon "^0.8.1"
- snapdragon-node "^2.0.1"
- split-string "^3.0.2"
- to-regex "^3.0.1"
-
braces@^3.0.1:
version "3.0.2"
- resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"
-browser-capabilities@^1.0.0:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/browser-capabilities/-/browser-capabilities-1.1.4.tgz#a6bd657a07a134532ad66c722b8949904478b973"
- integrity sha512-BezMQhbQklxjRQpZZQ8tnbzEo6AldUwMh8/PeWt5/CTBSwByQRXZEAK2fbnEahQ4poeeaI0suAYRq25A1YGOmw==
- dependencies:
- "@types/ua-parser-js" "^0.7.31"
- ua-parser-js "^0.7.15"
-
-browserify-zlib@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d"
- integrity sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=
- dependencies:
- pako "~0.2.0"
-
-browserslist@^4.14.5:
- version "4.16.3"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
- integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
- dependencies:
- caniuse-lite "^1.0.30001181"
- colorette "^1.2.1"
- electron-to-chromium "^1.3.649"
- escalade "^3.1.1"
- node-releases "^1.1.70"
-
-browserstack@^1.2.0:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/browserstack/-/browserstack-1.6.1.tgz#e051f9733ec3b507659f395c7a4765a1b1e358b3"
- integrity sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==
- dependencies:
- https-proxy-agent "^2.2.1"
-
-btoa-lite@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337"
- integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc=
-
-buffer-alloc-unsafe@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
- integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
-
-buffer-alloc@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
- integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
- dependencies:
- buffer-alloc-unsafe "^1.1.0"
- buffer-fill "^1.0.0"
-
-buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3:
- version "0.2.13"
- resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
- integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
-
-buffer-fill@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
- integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
-
buffer-from@^1.0.0:
- version "1.1.1"
- resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz"
- integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-buffer@^5.1.0, buffer@^5.5.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
- integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
- dependencies:
- base64-js "^1.3.1"
- ieee754 "^1.1.13"
-
-busboy@^0.2.11:
- version "0.2.14"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453"
- integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=
- dependencies:
- dicer "0.2.5"
- readable-stream "1.1.x"
-
-bytes@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
- integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
-
-bytes@3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
- integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
-
-cache-base@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
- integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
- dependencies:
- collection-visit "^1.0.0"
- component-emitter "^1.2.1"
- get-value "^2.0.6"
- has-value "^1.0.0"
- isobject "^3.0.1"
- set-value "^2.0.0"
- to-object-path "^0.3.0"
- union-value "^1.0.0"
- unset-value "^1.0.0"
-
-cacheable-lookup@^5.0.3:
- version "5.0.4"
- resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
- integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
cacheable-request@^6.0.0:
version "6.1.0"
- resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
dependencies:
clone-response "^1.0.2"
@@ -2611,151 +446,60 @@
normalize-url "^4.1.0"
responselike "^1.0.2"
-cacheable-request@^7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58"
- integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^4.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^4.1.0"
- responselike "^2.0.0"
-
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
- resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==
dependencies:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
-call-me-maybe@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
- integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-
callsites@^3.0.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camel-case@3.0.x:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
- integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
- dependencies:
- no-case "^2.2.0"
- upper-case "^1.1.1"
-
-camelcase-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
- integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
- dependencies:
- camelcase "^2.0.0"
- map-obj "^1.0.0"
-
camelcase-keys@^6.2.2:
version "6.2.2"
- resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
dependencies:
camelcase "^5.3.1"
map-obj "^4.0.0"
quick-lru "^4.0.1"
-camelcase@^2.0.0, camelcase@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
- integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-
-camelcase@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
- integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
-
camelcase@^5.3.1:
version "5.3.1"
- resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
camelcase@^6.2.0:
version "6.2.0"
- resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
-cancel-token@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/cancel-token/-/cancel-token-0.1.1.tgz#c18197674bb1c84c1d6933ebf15d8d5a5ce79b4f"
- integrity sha1-wYGXZ0uxyEwdaTPr8V2NWlznm08=
- dependencies:
- "@types/node" "^4.0.30"
-
-caniuse-lite@^1.0.30001181:
- version "1.0.30001208"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001208.tgz#a999014a35cebd4f98c405930a057a0d75352eb9"
- integrity sha512-OE5UE4+nBOro8Dyvv0lfx+SRtfVIOM9uhKqFmJeUbGriqhhStgp1A0OyBpgy3OUF8AhYCT+PVwPC1gMl2ZcQMA==
-
-capture-stack-trace@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
- integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
-
-caseless@~0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
- integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-
-chalk@*, chalk@^4.0.0, chalk@^4.1.0:
- version "4.1.0"
- resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz"
- integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
- integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
- dependencies:
- ansi-styles "^2.2.1"
- escape-string-regexp "^1.0.2"
- has-ansi "^2.0.0"
- strip-ansi "^3.0.0"
- supports-color "^2.0.0"
-
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2:
+chalk@^2.0.0:
version "2.4.2"
- resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
dependencies:
ansi-styles "^3.2.1"
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@~0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f"
- integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=
+chalk@^4.0.0, chalk@^4.1.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
dependencies:
- ansi-styles "~1.0.0"
- has-color "~0.1.0"
- strip-ansi "~0.1.0"
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
chardet@^0.7.0:
version "0.7.0"
- resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
-charenc@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
- integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
-
cheerio@1.0.0-rc.2:
version "1.0.0-rc.2"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
@@ -2768,380 +512,77 @@
lodash "^4.15.0"
parse5 "^3.0.1"
-chokidar@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
- integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=
- dependencies:
- anymatch "^1.3.0"
- async-each "^1.0.0"
- glob-parent "^2.0.0"
- inherits "^2.0.1"
- is-binary-path "^1.0.0"
- is-glob "^2.0.0"
- path-is-absolute "^1.0.0"
- readdirp "^2.0.0"
- optionalDependencies:
- fsevents "^1.0.0"
-
-chownr@^1.0.1:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
- integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
-
-ci-info@^1.5.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
- integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
-
ci-info@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-class-utils@^0.3.5:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
- integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
- dependencies:
- arr-union "^3.1.0"
- define-property "^0.2.5"
- isobject "^3.0.0"
- static-extend "^0.1.1"
-
-clean-css@4.2.x:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
- integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==
- dependencies:
- source-map "~0.6.0"
-
-cleankill@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/cleankill/-/cleankill-2.0.0.tgz#59830dfc8b411d53dc72ad09d45a78ea33161a91"
- integrity sha1-WYMN/ItBHVPccq0J1Fp46jMWGpE=
-
-cli-boxes@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
- integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
-
cli-boxes@^2.2.1:
version "2.2.1"
- resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
-cli-cursor@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
- integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=
- dependencies:
- restore-cursor "^1.0.1"
-
cli-cursor@^3.1.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
dependencies:
restore-cursor "^3.1.0"
-cli-table@^0.3.1:
- version "0.3.6"
- resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.6.tgz#e9d6aa859c7fe636981fd3787378c2a20bce92fc"
- integrity sha512-ZkNZbnZjKERTY5NwC2SeMeLeifSPq/pubeRoTpdr3WchLlnZg6hEgvHkK5zL7KNFdd9PmHN8lxrENUwI3cE8vQ==
- dependencies:
- colors "1.0.3"
-
-cli-width@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
- integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
-
cli-width@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
-clone-buffer@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58"
- integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg=
-
-clone-deep@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
- integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
- dependencies:
- is-plain-object "^2.0.4"
- kind-of "^6.0.2"
- shallow-clone "^3.0.0"
-
clone-response@^1.0.2:
version "1.0.2"
- resolved "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
-clone-stats@^0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1"
- integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=
-
-clone-stats@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680"
- integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=
-
-clone@^1.0.0:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
- integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
-
-clone@^2.0.0, clone@^2.1.0, clone@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
- integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
-
-cloneable-readable@^1.0.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec"
- integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==
- dependencies:
- inherits "^2.0.1"
- process-nextick-args "^2.0.0"
- readable-stream "^2.3.5"
-
-code-point-at@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
- integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
-
-collection-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
- integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
- dependencies:
- map-visit "^1.0.0"
- object-visit "^1.0.0"
-
-color-convert@^1.9.0, color-convert@^1.9.1:
+color-convert@^1.9.0:
version "1.9.3"
- resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
dependencies:
color-name "1.1.3"
color-convert@^2.0.1:
version "2.0.1"
- resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@1.1.3:
version "1.1.3"
- resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-color-name@^1.0.0, color-name@~1.1.4:
+color-name@~1.1.4:
version "1.1.4"
- resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-color-string@^1.5.2:
- version "1.5.5"
- resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014"
- integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==
- dependencies:
- color-name "^1.0.0"
- simple-swizzle "^0.2.2"
-
-color@3.0.x:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a"
- integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==
- dependencies:
- color-convert "^1.9.1"
- color-string "^1.5.2"
-
-colorette@^1.2.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
- integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
-
-colors@1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
- integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=
-
-colors@^1.2.1:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
- integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
-
-colorspace@1.1.x:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
- integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
- dependencies:
- color "3.0.x"
- text-hex "1.0.x"
-
-combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
- version "1.0.8"
- resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
- integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
- dependencies:
- delayed-stream "~1.0.0"
-
-command-line-args@^5.0.2:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a"
- integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==
- dependencies:
- array-back "^3.0.1"
- find-replace "^3.0.0"
- lodash.camelcase "^4.3.0"
- typical "^4.0.0"
-
-command-line-commands@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/command-line-commands/-/command-line-commands-2.0.1.tgz#c58aa13dc78c06038ed67077e57ad09a6f858f46"
- integrity sha512-m8c2p1DrNd2ruIAggxd/y6DgygQayf6r8RHwchhXryaLF8I6koYjoYroVP+emeROE9DXN5b9sP1Gh+WtvTTdtQ==
- dependencies:
- array-back "^2.0.0"
-
-command-line-usage@^5.0.5:
- version "5.0.5"
- resolved "https://registry.yarnpkg.com/command-line-usage/-/command-line-usage-5.0.5.tgz#5f25933ffe6dedd983c635d38a21d7e623fda357"
- integrity sha512-d8NrGylA5oCXSbGoKz05FkehDAzSmIm4K03S5VDh4d5lZAtTWfc3D1RuETtuQCn8129nYfJfDdF7P/lwcz1BlA==
- dependencies:
- array-back "^2.0.0"
- chalk "^2.4.1"
- table-layout "^0.4.3"
- typical "^2.6.1"
-
-commander@2.17.x:
- version "2.17.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
- integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
-
-commander@^2.20.0, commander@^2.20.3:
+commander@^2.20.0:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-commander@~2.19.0:
- version "2.19.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
- integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
-
-comment-parser@1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.1.2.tgz#e5317d7a2ec22b470dcb54a29b25426c30bf39d8"
- integrity sha512-AOdq0i8ghZudnYv8RUnHrhTgafUGs61Rdz9jemU5x2lnZwAWyOq7vySo626K59e1fVKH1xSRorJwPVRLSWOoAQ==
-
-commondir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
- integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
-
-component-bind@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
- integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=
-
-component-emitter@1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
- integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=
-
-component-emitter@^1.2.1, component-emitter@~1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
- integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
-
-component-inherit@0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
- integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=
-
-compress-commons@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-2.1.1.tgz#9410d9a534cf8435e3fbbb7c6ce48de2dc2f0610"
- integrity sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==
- dependencies:
- buffer-crc32 "^0.2.13"
- crc32-stream "^3.0.1"
- normalize-path "^3.0.0"
- readable-stream "^2.3.6"
-
-compressible@~2.0.16:
- version "2.0.18"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
- integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
- dependencies:
- mime-db ">= 1.43.0 < 2"
-
-compression@^1.6.2:
- version "1.7.4"
- resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
- integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
- dependencies:
- accepts "~1.3.5"
- bytes "3.0.0"
- compressible "~2.0.16"
- debug "2.6.9"
- on-headers "~1.0.2"
- safe-buffer "5.1.2"
- vary "~1.1.2"
+comment-parser@1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.1.5.tgz#453627ef8f67dbcec44e79a9bd5baa37f0bce9b2"
+ integrity sha512-RePCE4leIhBlmrqiYTvaqEeGYg7qpSl4etaIabKtdOQVi+mSTIBBklGUwIr79GXYnl3LpMwmDw4KeR2stNc6FA==
concat-map@0.0.1:
version "0.0.1"
- resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-concat-stream@^1.4.7, concat-stream@^1.5.2:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
- integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
- dependencies:
- buffer-from "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^2.2.2"
- typedarray "^0.0.6"
-
-configstore@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-2.1.0.tgz#737a3a7036e9886102aa6099e47bb33ab1aba1a1"
- integrity sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=
- dependencies:
- dot-prop "^3.0.0"
- graceful-fs "^4.1.2"
- mkdirp "^0.5.0"
- object-assign "^4.0.1"
- os-tmpdir "^1.0.0"
- osenv "^0.1.0"
- uuid "^2.0.1"
- write-file-atomic "^1.1.2"
- xdg-basedir "^2.0.0"
-
-configstore@^3.0.0:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.5.tgz#e9af331fadc14dabd544d3e7e76dc446a09a530f"
- integrity sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA==
- dependencies:
- dot-prop "^4.2.1"
- graceful-fs "^4.1.2"
- make-dir "^1.0.0"
- unique-string "^1.0.0"
- write-file-atomic "^2.0.0"
- xdg-basedir "^3.0.0"
-
configstore@^5.0.1:
version "5.0.1"
- resolved "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
dependencies:
dot-prop "^5.2.0"
@@ -3151,132 +592,18 @@
write-file-atomic "^3.0.0"
xdg-basedir "^4.0.0"
-contains-path@^0.1.0:
- version "0.1.0"
- resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz"
- integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
-
-content-disposition@0.5.3:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
- integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
- dependencies:
- safe-buffer "5.1.2"
-
-content-type@^1.0.2, content-type@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
- integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
-
-convert-source-map@^1.1.1, convert-source-map@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
- integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
- dependencies:
- safe-buffer "~5.1.1"
-
-cookie-signature@1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
- integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-
-cookie@0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
- integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
-
-cookie@~0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
- integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
-
-copy-descriptor@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
- integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-
-core-js@^2.4.0:
- version "2.6.12"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec"
- integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==
-
-core-util-is@1.0.2, core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
-
-cors@^2.8.4:
- version "2.8.5"
- resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
- integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
- dependencies:
- object-assign "^4"
- vary "^1"
-
-crc32-stream@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85"
- integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==
- dependencies:
- crc "^3.4.4"
- readable-stream "^3.4.0"
-
-crc@^3.4.4:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
- integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
- dependencies:
- buffer "^5.1.0"
-
-create-error-class@^3.0.0, create-error-class@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
- integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
- dependencies:
- capture-stack-trace "^1.0.0"
-
-cross-spawn@^5.0.1:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
- integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
- dependencies:
- lru-cache "^4.0.1"
- shebang-command "^1.2.0"
- which "^1.2.9"
-
-cross-spawn@^6.0.0, cross-spawn@^6.0.5:
- version "6.0.5"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
- integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
- dependencies:
- nice-try "^1.0.4"
- path-key "^2.0.1"
- semver "^5.5.0"
- shebang-command "^1.2.0"
- which "^1.2.9"
-
-cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
+cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
- resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
-crypt@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
- integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
-
-crypto-random-string@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
- integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
-
crypto-random-string@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
css-select@~1.2.0:
@@ -3289,287 +616,82 @@
domutils "1.5.1"
nth-check "~1.0.1"
-css-slam@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/css-slam/-/css-slam-2.1.2.tgz#3d35b1922cb3e0002a45c89ab189492508c493e5"
- integrity sha512-cObrY+mhFEmepWpua6EpMrgRNTQ0eeym+kvR0lukI6hDEzK7F8himEDS4cJ9+fPHCoArTzVrrR0d+oAUbTR1NA==
- dependencies:
- command-line-args "^5.0.2"
- command-line-usage "^5.0.5"
- dom5 "^3.0.0"
- parse5 "^4.0.0"
- shady-css-parser "^0.1.0"
-
-css-what@2.1, css-what@^2.1.0:
+css-what@2.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
-cssbeautify@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/cssbeautify/-/cssbeautify-0.3.1.tgz#12dd1f734035c2e6faca67dcbdcef74e42811397"
- integrity sha1-Et0fc0A1wub6ymfcvc73TkKBE5c=
-
-currently-unhandled@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
- integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
- dependencies:
- array-find-index "^1.0.1"
-
-dargs@^6.0.0, dargs@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/dargs/-/dargs-6.1.0.tgz#1f3b9b56393ecf8caa7cbfd6c31496ffcfb9b272"
- integrity sha512-5dVBvpBLBnPwSsYXqfybFyehMmC/EenKEcf23AhCTgTf48JFBbmJKqoZBsERDnjL0FyiVTYWdFsRfTLHxLyKdQ==
-
-dashdash@^1.12.0:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
- integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
- dependencies:
- assert-plus "^1.0.0"
-
-dateformat@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
- integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
-
-debug@2.6.9, debug@^2.0.0, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
+debug@^2.6.9:
version "2.6.9"
- resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
-debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
- version "4.3.1"
- resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
- integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
- dependencies:
- ms "2.1.2"
-
-debug@^3.1.0:
+debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
dependencies:
ms "^2.1.1"
-debug@~3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
- integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+debug@^4.0.1, debug@^4.1.1, debug@^4.3.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
+ integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
dependencies:
- ms "2.0.0"
-
-debug@~4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
- integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
- dependencies:
- ms "^2.1.1"
+ ms "2.1.2"
decamelize-keys@^1.1.0:
version "1.1.0"
- resolved "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
dependencies:
decamelize "^1.1.0"
map-obj "^1.0.0"
-decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0:
+decamelize@^1.1.0, decamelize@^1.2.0:
version "1.2.0"
- resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-decode-uri-component@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
- integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
-
-decompress-response@^3.2.0, decompress-response@^3.3.0:
+decompress-response@^3.3.0:
version "3.3.0"
- resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
dependencies:
mimic-response "^1.0.0"
-decompress-response@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
- integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
- dependencies:
- mimic-response "^3.1.0"
-
-deep-extend@^0.5.1:
- version "0.5.1"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.5.1.tgz#b894a9dd90d3023fbf1c55a394fb858eb2066f1f"
- integrity sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==
-
-deep-extend@^0.6.0, deep-extend@~0.6.0:
+deep-extend@^0.6.0:
version "0.6.0"
- resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
deep-is@^0.1.3:
version "0.1.3"
- resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
defer-to-connect@^1.0.1:
version "1.1.3"
- resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-defer-to-connect@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
- integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
-
define-properties@^1.1.3:
version "1.1.3"
- resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
dependencies:
object-keys "^1.0.12"
-define-property@^0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
- integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
- dependencies:
- is-descriptor "^0.1.0"
-
-define-property@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
- integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
- dependencies:
- is-descriptor "^1.0.0"
-
-define-property@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
- integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
- dependencies:
- is-descriptor "^1.0.2"
- isobject "^3.0.1"
-
-del@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
- integrity sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=
- dependencies:
- globby "^6.1.0"
- is-path-cwd "^1.0.0"
- is-path-in-cwd "^1.0.0"
- p-map "^1.1.1"
- pify "^3.0.0"
- rimraf "^2.2.8"
-
-delayed-stream@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
- integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-
-depd@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
- integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
-
-deprecation@^2.0.0, deprecation@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919"
- integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==
-
-destroy@~1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
- integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
-
-detect-conflict@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/detect-conflict/-/detect-conflict-1.0.1.tgz#088657a66a961c05019db7c4230883b1c6b4176e"
- integrity sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=
-
-detect-file@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63"
- integrity sha1-STXe39lIhkjgBrASlWbpOGcR6mM=
- dependencies:
- fs-exists-sync "^0.1.0"
-
-detect-file@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
- integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
-
-detect-indent@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
- integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg=
- dependencies:
- repeating "^2.0.0"
-
-detect-node@^2.0.3:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.5.tgz#9d270aa7eaa5af0b72c4c9d9b814e7f4ce738b79"
- integrity sha512-qi86tE6hRcFHy8jI1m2VG+LaPUR1LhqDa5G8tVjuUXmOrpuAgqsA1pN0+ldgr3aKUH+QLI9hCY/OcRYisERejw==
-
-dicer@0.2.5:
- version "0.2.5"
- resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f"
- integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=
- dependencies:
- readable-stream "1.1.x"
- streamsearch "0.1.2"
-
-diff@^2.1.2:
- version "2.2.3"
- resolved "https://registry.yarnpkg.com/diff/-/diff-2.2.3.tgz#60eafd0d28ee906e4e8ff0a52c1229521033bf99"
- integrity sha1-YOr9DSjukG5Oj/ClLBIpUhAzv5k=
-
-diff@^3.1.0, diff@^3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
- integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
-
-diff@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
- integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
-
-dir-glob@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.0.0.tgz#0b205d2b6aef98238ca286598a8204d29d0a0034"
- integrity sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==
- dependencies:
- arrify "^1.0.1"
- path-type "^3.0.0"
-
-dir-glob@^2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
- integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==
- dependencies:
- path-type "^3.0.0"
-
dir-glob@^3.0.1:
version "3.0.1"
- resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
dependencies:
path-type "^4.0.0"
-doctrine@1.5.0:
- version "1.5.0"
- resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz"
- integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
- dependencies:
- esutils "^2.0.2"
- isarray "^1.0.0"
-
-doctrine@^2.0.2:
+doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
@@ -3578,7 +700,7 @@
doctrine@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
dependencies:
esutils "^2.0.2"
@@ -3592,12 +714,12 @@
entities "^2.0.0"
dom-serializer@^1.0.1:
- version "1.3.1"
- resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.1.tgz"
- integrity sha512-Pv2ZluG5ife96udGgEDovOOOA5UELkltfJpnIExPrAk1LTvecolUGn6lIaoLh86d83GiB86CjzciMd9BuRB71Q==
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91"
+ integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==
dependencies:
domelementtype "^2.0.1"
- domhandler "^4.0.0"
+ domhandler "^4.2.0"
entities "^2.0.0"
dom-serializer@~0.1.0:
@@ -3608,22 +730,6 @@
domelementtype "^1.3.0"
entities "^1.1.1"
-dom-urls@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/dom-urls/-/dom-urls-1.1.0.tgz#001ddf81628cd1e706125c7176f53ccec55d918e"
- integrity sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=
- dependencies:
- urijs "^1.16.1"
-
-dom5@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/dom5/-/dom5-3.0.1.tgz#cdfc7331f376e284bf379e6ea054afc136702944"
- integrity sha512-JPFiouQIr16VQ4dX6i0+Hpbg3H2bMKPmZ+WZgBOSSvOPx9QHwwY8sPzeM2baUtViESYto6wC2nuZOMC/6gulcA==
- dependencies:
- "@types/parse5" "^2.2.34"
- clone "^2.1.0"
- parse5 "^4.0.0"
-
domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
@@ -3631,7 +737,7 @@
domelementtype@^2.0.1, domelementtype@^2.2.0:
version "2.2.0"
- resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57"
integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==
domhandler@^2.3.0:
@@ -3641,10 +747,10 @@
dependencies:
domelementtype "1"
-domhandler@^4.0.0, domhandler@^4.1.0:
- version "4.1.0"
- resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.1.0.tgz"
- integrity sha512-/6/kmsGlMY4Tup/nGVutdrK9yQi4YjWVcVeoQmixpzjOUK1U7pQkvAPHBJeUxOgxF0J8f8lwCJSlCfD0V4CMGQ==
+domhandler@^4.0.0, domhandler@^4.2.0:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f"
+ integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==
dependencies:
domelementtype "^2.2.0"
@@ -3665,184 +771,46 @@
domelementtype "1"
domutils@^2.5.2:
- version "2.5.2"
- resolved "https://registry.npmjs.org/domutils/-/domutils-2.5.2.tgz"
- integrity sha512-MHTthCb1zj8f1GVfRpeZUbohQf/HdBos0oX5gZcQFepOZPLLRyj6Wn7XS7EMnY7CVpwv8863u2vyE83Hfu28HQ==
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
dependencies:
dom-serializer "^1.0.1"
domelementtype "^2.2.0"
- domhandler "^4.1.0"
-
-dot-prop@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
- integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc=
- dependencies:
- is-obj "^1.0.0"
-
-dot-prop@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4"
- integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==
- dependencies:
- is-obj "^1.0.0"
+ domhandler "^4.2.0"
dot-prop@^5.2.0:
version "5.3.0"
- resolved "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
dependencies:
is-obj "^2.0.0"
-download-stats@^0.3.4:
- version "0.3.4"
- resolved "https://registry.yarnpkg.com/download-stats/-/download-stats-0.3.4.tgz#67ea0c32f14acd9f639da704eef509684ba2dae7"
- integrity sha512-ic2BigbyUWx7/CBbsfGjf71zUNZB4edBGC3oRliSzsoNmvyVx3Ycfp1w3vp2Y78Ee0eIIkjIEO5KzW0zThDGaA==
- dependencies:
- JSONStream "^1.2.1"
- lazy-cache "^2.0.1"
- moment "^2.15.1"
-
-duplexer2@^0.1.2, duplexer2@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
- integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=
- dependencies:
- readable-stream "^2.0.2"
-
duplexer3@^0.1.4:
version "0.1.4"
- resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz"
+ resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
-duplexify@^3.2.0, duplexify@^3.5.0, duplexify@^3.6.0:
- version "3.7.1"
- resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
- integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
- dependencies:
- end-of-stream "^1.0.0"
- inherits "^2.0.1"
- readable-stream "^2.0.0"
- stream-shift "^1.0.0"
-
-ecc-jsbn@~0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
- integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
- dependencies:
- jsbn "~0.1.0"
- safer-buffer "^2.1.0"
-
-editions@^2.2.0:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/editions/-/editions-2.3.1.tgz#3bc9962f1978e801312fbd0aebfed63b49bfe698"
- integrity sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA==
- dependencies:
- errlop "^2.0.0"
- semver "^6.3.0"
-
-ee-first@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
- integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-
-ejs@^2.5.9, ejs@^2.6.1:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba"
- integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==
-
-ejs@^3.1.5:
- version "3.1.6"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.6.tgz#5bfd0a0689743bb5268b3550cceeebbc1702822a"
- integrity sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==
- dependencies:
- jake "^10.6.1"
-
-electron-to-chromium@^1.3.649:
- version "1.3.712"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.712.tgz#ae467ffe5f95961c6d41ceefe858fc36eb53b38f"
- integrity sha512-3kRVibBeCM4vsgoHHGKHmPocLqtFAGTrebXxxtgKs87hNUzXrX2NuS3jnBys7IozCnw7viQlozxKkmty2KNfrw==
-
-emitter-component@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/emitter-component/-/emitter-component-1.1.1.tgz#065e2dbed6959bf470679edabeaf7981d1003ab6"
- integrity sha1-Bl4tvtaVm/RwZ57avq95gdEAOrY=
-
emoji-regex@^7.0.1:
version "7.0.3"
- resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0:
version "8.0.0"
- resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-enabled@2.0.x:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
- integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
-
-encodeurl@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
- integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-
-end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+end-of-stream@^1.1.0:
version "1.4.4"
- resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
dependencies:
once "^1.4.0"
-ends-with@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/ends-with/-/ends-with-0.2.0.tgz#2f9da98d57a50cfda4571ce4339000500f4e6b8a"
- integrity sha1-L52pjVelDP2kVxzkM5AAUA9Oa4o=
-
-engine.io-client@~3.5.0:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.5.1.tgz#b500458a39c0cd197a921e0e759721a746d0bdb9"
- integrity sha512-oVu9kBkGbcggulyVF0kz6BV3ganqUeqXvD79WOFKa+11oK692w1NyFkuEj4xrkFRpZhn92QOqTk4RQq5LiBXbQ==
- dependencies:
- component-emitter "~1.3.0"
- component-inherit "0.0.3"
- debug "~3.1.0"
- engine.io-parser "~2.2.0"
- has-cors "1.1.0"
- indexof "0.0.1"
- parseqs "0.0.6"
- parseuri "0.0.6"
- ws "~7.4.2"
- xmlhttprequest-ssl "~1.5.4"
- yeast "0.1.2"
-
-engine.io-parser@~2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7"
- integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg==
- dependencies:
- after "0.8.2"
- arraybuffer.slice "~0.0.7"
- base64-arraybuffer "0.1.4"
- blob "0.0.5"
- has-binary2 "~1.0.2"
-
-engine.io@~3.5.0:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.5.0.tgz#9d6b985c8a39b1fe87cd91eb014de0552259821b"
- integrity sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==
- dependencies:
- accepts "~1.3.4"
- base64id "2.0.0"
- cookie "~0.4.1"
- debug "~4.1.0"
- engine.io-parser "~2.2.0"
- ws "~7.4.2"
-
enquirer@^2.3.5:
version "2.3.6"
- resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
+ resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
dependencies:
ansi-colors "^4.1.1"
@@ -3854,32 +822,20 @@
entities@^2.0.0:
version "2.2.0"
- resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
-errlop@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b"
- integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw==
-
-error-ex@^1.2.0, error-ex@^1.3.1:
+error-ex@^1.3.1:
version "1.3.2"
- resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
-error@^7.0.2:
- version "7.2.1"
- resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894"
- integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==
- dependencies:
- string-template "~0.2.1"
-
-es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2:
- version "1.18.0"
- resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz"
- integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==
+es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2:
+ version "1.18.5"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19"
+ integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
@@ -3887,92 +843,71 @@
get-intrinsic "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.2"
+ internal-slot "^1.0.3"
is-callable "^1.2.3"
is-negative-zero "^2.0.1"
- is-regex "^1.1.2"
- is-string "^1.0.5"
- object-inspect "^1.9.0"
+ is-regex "^1.1.3"
+ is-string "^1.0.6"
+ object-inspect "^1.11.0"
object-keys "^1.1.1"
object.assign "^4.1.2"
string.prototype.trimend "^1.0.4"
string.prototype.trimstart "^1.0.4"
- unbox-primitive "^1.0.0"
+ unbox-primitive "^1.0.1"
es-to-primitive@^1.2.1:
version "1.2.1"
- resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==
dependencies:
is-callable "^1.1.4"
is-date-object "^1.0.1"
is-symbol "^1.0.2"
-es6-promise@^4.0.3, es6-promise@^4.0.5:
- version "4.2.8"
- resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
- integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
-
-es6-promisify@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
- integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
- dependencies:
- es6-promise "^4.0.3"
-
-es6-promisify@^6.0.0:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
- integrity sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
escape-goat@^2.0.0:
version "2.1.1"
- resolved "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
-escape-html@^1.0.3, escape-html@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
- integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
-
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
+escape-string-regexp@^1.0.5:
version "1.0.5"
- resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
eslint-config-google@^0.14.0:
version "0.14.0"
- resolved "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.14.0.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-config-google/-/eslint-config-google-0.14.0.tgz#4f5f8759ba6e11b424294a219dbfa18c508bcc1a"
integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==
eslint-config-prettier@^7.0.0:
version "7.2.0"
- resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz#f4a4bd2832e810e8cc7c1411ec85b3e85c0c53f9"
integrity sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==
-eslint-import-resolver-node@^0.3.4:
- version "0.3.4"
- resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz"
- integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
+eslint-import-resolver-node@^0.3.6:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd"
+ integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==
dependencies:
- debug "^2.6.9"
- resolve "^1.13.1"
+ debug "^3.2.7"
+ resolve "^1.20.0"
-eslint-module-utils@^2.6.0:
- version "2.6.0"
- resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz"
- integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==
+eslint-module-utils@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz#94e5540dd15fe1522e8ffa3ec8db3b7fa7e7a534"
+ integrity sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==
dependencies:
- debug "^2.6.9"
+ debug "^3.2.7"
pkg-dir "^2.0.0"
eslint-plugin-es@^3.0.0:
version "3.0.1"
- resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893"
integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==
dependencies:
eslint-utils "^2.0.0"
@@ -3986,40 +921,51 @@
htmlparser2 "^6.0.1"
eslint-plugin-import@^2.22.1:
- version "2.22.1"
- resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz"
- integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==
+ version "2.24.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz#2c8cd2e341f3885918ee27d18479910ade7bb4da"
+ integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q==
dependencies:
- array-includes "^3.1.1"
- array.prototype.flat "^1.2.3"
- contains-path "^0.1.0"
+ array-includes "^3.1.3"
+ array.prototype.flat "^1.2.4"
debug "^2.6.9"
- doctrine "1.5.0"
- eslint-import-resolver-node "^0.3.4"
- eslint-module-utils "^2.6.0"
+ doctrine "^2.1.0"
+ eslint-import-resolver-node "^0.3.6"
+ eslint-module-utils "^2.6.2"
+ find-up "^2.0.0"
has "^1.0.3"
+ is-core-module "^2.6.0"
minimatch "^3.0.4"
- object.values "^1.1.1"
- read-pkg-up "^2.0.0"
- resolve "^1.17.0"
- tsconfig-paths "^3.9.0"
+ object.values "^1.1.4"
+ pkg-up "^2.0.0"
+ read-pkg-up "^3.0.0"
+ resolve "^1.20.0"
+ tsconfig-paths "^3.11.0"
eslint-plugin-jsdoc@^32.3.0:
- version "32.3.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.0.tgz#7c9fa5da8c72bd6ad7d97bbf8dee8bc29bec3f9e"
- integrity sha512-zyx7kajDK+tqS1bHuY5sapkad8P8KT0vdd/lE55j47VPG2MeenSYuIY/M/Pvmzq5g0+3JB+P3BJGUXmHxtuKPQ==
+ version "32.3.4"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.4.tgz#6888f3b2dbb9f73fb551458c639a4e8c84fe9ddc"
+ integrity sha512-xSWfsYvffXnN0OkwLnB7MoDDDDjqcp46W7YlY1j7JyfAQBQ+WnGCfLov3gVNZjUGtK9Otj8mEhTZTqJu4QtIGA==
dependencies:
- comment-parser "1.1.2"
+ comment-parser "1.1.5"
debug "^4.3.1"
jsdoctypeparser "^9.0.0"
- lodash "^4.17.20"
+ lodash "^4.17.21"
regextras "^0.7.1"
- semver "^7.3.4"
+ semver "^7.3.5"
spdx-expression-parse "^3.0.1"
+eslint-plugin-lit@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-lit/-/eslint-plugin-lit-1.5.1.tgz#e5b86fee4aeb6023ad4bb90b3d9e462ca8eff755"
+ integrity sha512-pYB0QM11uyOk5L55QfGhBmWi8a56PkNsnx+zVpY4bxz9YVquEo4BeRnFmf9AwFyT89rhGud9QruFhM2xJ4piwg==
+ dependencies:
+ parse5 "^6.0.1"
+ parse5-htmlparser2-tree-adapter "^6.0.1"
+ requireindex "^1.2.0"
+
eslint-plugin-node@^11.1.0:
version "11.1.0"
- resolved "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d"
integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==
dependencies:
eslint-plugin-es "^3.0.0"
@@ -4029,23 +975,21 @@
resolve "^1.10.1"
semver "^6.1.0"
-eslint-plugin-prettier@^3.1.4:
- version "3.3.1"
- resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz"
- integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==
+eslint-plugin-prettier@^3.1.4, eslint-plugin-prettier@^3.4.0:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5"
+ integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==
dependencies:
prettier-linter-helpers "^1.0.0"
-eslint-plugin-prettier@^3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7"
- integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==
- dependencies:
- prettier-linter-helpers "^1.0.0"
+eslint-plugin-regex@^1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-regex/-/eslint-plugin-regex-1.8.0.tgz#4bd111cf5235fb76a4a7f77d7ffcb7b3777b8a77"
+ integrity sha512-rmzVvpoxHKgvcYDo9d1X9RMFOtyOV3A6taD3KWE6gIID2dHoc8RPd0YAjDSJ0LG35wnehQBfsNB+F7q4eYqXqw==
-eslint-scope@^5.0.0, eslint-scope@^5.1.1:
+eslint-scope@^5.1.1:
version "5.1.1"
- resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
dependencies:
esrecurse "^4.3.0"
@@ -4053,7 +997,7 @@
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
@@ -4067,36 +1011,39 @@
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
version "1.3.0"
- resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-visitor-keys@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz"
- integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
+ integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
-eslint@^7.10.0:
- version "7.23.0"
- resolved "https://registry.npmjs.org/eslint/-/eslint-7.23.0.tgz"
- integrity sha512-kqvNVbdkjzpFy0XOszNwjkKzZ+6TcwCQ/h+ozlcIWwaimBBuhlQ4nN6kbiM2L+OjDcznkTJxzYfRFH92sx4a0Q==
+eslint@^7.10.0, eslint@^7.24.0:
+ version "7.32.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
+ integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
dependencies:
"@babel/code-frame" "7.12.11"
- "@eslint/eslintrc" "^0.4.0"
+ "@eslint/eslintrc" "^0.4.3"
+ "@humanwhocodes/config-array" "^0.5.0"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
debug "^4.0.1"
doctrine "^3.0.0"
enquirer "^2.3.5"
+ escape-string-regexp "^4.0.0"
eslint-scope "^5.1.1"
eslint-utils "^2.1.0"
eslint-visitor-keys "^2.0.0"
espree "^7.3.1"
esquery "^1.4.0"
esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
functional-red-black-tree "^1.0.1"
- glob-parent "^5.0.0"
+ glob-parent "^5.1.2"
globals "^13.6.0"
ignore "^4.0.6"
import-fresh "^3.0.0"
@@ -4105,7 +1052,7 @@
js-yaml "^3.13.1"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.4.1"
- lodash "^4.17.21"
+ lodash.merge "^4.6.2"
minimatch "^3.0.4"
natural-compare "^1.4.0"
optionator "^0.9.1"
@@ -4114,64 +1061,13 @@
semver "^7.2.1"
strip-ansi "^6.0.0"
strip-json-comments "^3.1.0"
- table "^6.0.4"
+ table "^6.0.9"
text-table "^0.2.0"
v8-compile-cache "^2.0.3"
-eslint@^7.24.0:
- version "7.24.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.24.0.tgz#2e44fa62d93892bfdb100521f17345ba54b8513a"
- integrity sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==
- dependencies:
- "@babel/code-frame" "7.12.11"
- "@eslint/eslintrc" "^0.4.0"
- ajv "^6.10.0"
- chalk "^4.0.0"
- cross-spawn "^7.0.2"
- debug "^4.0.1"
- doctrine "^3.0.0"
- enquirer "^2.3.5"
- eslint-scope "^5.1.1"
- eslint-utils "^2.1.0"
- eslint-visitor-keys "^2.0.0"
- espree "^7.3.1"
- esquery "^1.4.0"
- esutils "^2.0.2"
- file-entry-cache "^6.0.1"
- functional-red-black-tree "^1.0.1"
- glob-parent "^5.0.0"
- globals "^13.6.0"
- ignore "^4.0.6"
- import-fresh "^3.0.0"
- imurmurhash "^0.1.4"
- is-glob "^4.0.0"
- js-yaml "^3.13.1"
- json-stable-stringify-without-jsonify "^1.0.1"
- levn "^0.4.1"
- lodash "^4.17.21"
- minimatch "^3.0.4"
- natural-compare "^1.4.0"
- optionator "^0.9.1"
- progress "^2.0.0"
- regexpp "^3.1.0"
- semver "^7.2.1"
- strip-ansi "^6.0.0"
- strip-json-comments "^3.1.0"
- table "^6.0.4"
- text-table "^0.2.0"
- v8-compile-cache "^2.0.3"
-
-espree@^3.5.2:
- version "3.5.4"
- resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
- integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
- dependencies:
- acorn "^5.5.0"
- acorn-jsx "^3.0.0"
-
espree@^7.3.0, espree@^7.3.1:
version "7.3.1"
- resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
dependencies:
acorn "^7.4.0"
@@ -4180,93 +1076,42 @@
esprima@^4.0.0:
version "4.0.1"
- resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
esquery@^1.4.0:
version "1.4.0"
- resolved "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5"
integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==
dependencies:
estraverse "^5.1.0"
esrecurse@^4.3.0:
version "4.3.0"
- resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
dependencies:
estraverse "^5.2.0"
estraverse@^4.1.1:
version "4.3.0"
- resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
estraverse@^5.1.0, estraverse@^5.2.0:
version "5.2.0"
- resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
esutils@^2.0.2:
version "2.0.3"
- resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-etag@~1.8.1:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
- integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
-
-eventemitter3@^4.0.0:
- version "4.0.7"
- resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
- integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
-
-execa@^0.7.0:
- version "0.7.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
- integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
- dependencies:
- cross-spawn "^5.0.1"
- get-stream "^3.0.0"
- is-stream "^1.1.0"
- npm-run-path "^2.0.0"
- p-finally "^1.0.0"
- signal-exit "^3.0.0"
- strip-eof "^1.0.0"
-
-execa@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
- integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
- dependencies:
- cross-spawn "^6.0.0"
- get-stream "^4.0.0"
- is-stream "^1.1.0"
- npm-run-path "^2.0.0"
- p-finally "^1.0.0"
- signal-exit "^3.0.0"
- strip-eof "^1.0.0"
-
-execa@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
- integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
- dependencies:
- cross-spawn "^7.0.0"
- get-stream "^5.0.0"
- human-signals "^1.1.1"
- is-stream "^2.0.0"
- merge-stream "^2.0.0"
- npm-run-path "^4.0.0"
- onetime "^5.1.0"
- signal-exit "^3.0.2"
- strip-final-newline "^2.0.0"
-
execa@^5.0.0:
- version "5.0.0"
- resolved "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz"
- integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
dependencies:
cross-spawn "^7.0.3"
get-stream "^6.0.0"
@@ -4278,688 +1123,161 @@
signal-exit "^3.0.3"
strip-final-newline "^2.0.0"
-exit-hook@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
- integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=
-
-expand-brackets@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"
- integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=
- dependencies:
- is-posix-bracket "^0.1.0"
-
-expand-brackets@^2.1.4:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
- integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
- dependencies:
- debug "^2.3.3"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- posix-character-classes "^0.1.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-expand-range@^1.8.1:
- version "1.8.2"
- resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337"
- integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=
- dependencies:
- fill-range "^2.1.0"
-
-expand-tilde@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449"
- integrity sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=
- dependencies:
- os-homedir "^1.0.1"
-
-expand-tilde@^2.0.0, expand-tilde@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
- integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
- dependencies:
- homedir-polyfill "^1.0.1"
-
-express@^4.15.3, express@^4.8.5:
- version "4.17.1"
- resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
- integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
- dependencies:
- accepts "~1.3.7"
- array-flatten "1.1.1"
- body-parser "1.19.0"
- content-disposition "0.5.3"
- content-type "~1.0.4"
- cookie "0.4.0"
- cookie-signature "1.0.6"
- debug "2.6.9"
- depd "~1.1.2"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- finalhandler "~1.1.2"
- fresh "0.5.2"
- merge-descriptors "1.0.1"
- methods "~1.1.2"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- path-to-regexp "0.1.7"
- proxy-addr "~2.0.5"
- qs "6.7.0"
- range-parser "~1.2.1"
- safe-buffer "5.1.2"
- send "0.17.1"
- serve-static "1.14.1"
- setprototypeof "1.1.1"
- statuses "~1.5.0"
- type-is "~1.6.18"
- utils-merge "1.0.1"
- vary "~1.1.2"
-
-ext-list@^2.0.0:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37"
- integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
- dependencies:
- mime-db "^1.28.0"
-
-extend-shallow@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
- integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
- dependencies:
- is-extendable "^0.1.0"
-
-extend-shallow@^3.0.0, extend-shallow@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
- integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
- dependencies:
- assign-symbols "^1.0.0"
- is-extendable "^1.0.1"
-
-extend@^3.0.0, extend@~3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
- integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-
-external-editor@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-1.1.1.tgz#12d7b0db850f7ff7e7081baf4005700060c4600b"
- integrity sha1-Etew24UPf/fnCBuvQAVwAGDEYAs=
- dependencies:
- extend "^3.0.0"
- spawn-sync "^1.0.15"
- tmp "^0.0.29"
-
external-editor@^3.0.3:
version "3.1.0"
- resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
dependencies:
chardet "^0.7.0"
iconv-lite "^0.4.24"
tmp "^0.0.33"
-extglob@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
- integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=
- dependencies:
- is-extglob "^1.0.0"
-
-extglob@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
- integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
- dependencies:
- array-unique "^0.3.2"
- define-property "^1.0.0"
- expand-brackets "^2.1.4"
- extend-shallow "^2.0.1"
- fragment-cache "^0.2.1"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-extsprintf@1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
- integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
-
-extsprintf@^1.2.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
- integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
-
-fast-deep-equal@^3.1.1:
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
- resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-diff@^1.1.2:
version "1.2.0"
- resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
-fast-glob@^2.0.2, fast-glob@^2.2.6:
- version "2.2.7"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
- integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
- dependencies:
- "@mrmlnc/readdir-enhanced" "^2.2.1"
- "@nodelib/fs.stat" "^1.1.2"
- glob-parent "^3.1.0"
- is-glob "^4.0.0"
- merge2 "^1.2.3"
- micromatch "^3.1.10"
-
fast-glob@^3.1.1:
- version "3.2.5"
- resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz"
- integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
+ integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
dependencies:
"@nodelib/fs.stat" "^2.0.2"
"@nodelib/fs.walk" "^1.2.3"
- glob-parent "^5.1.0"
+ glob-parent "^5.1.2"
merge2 "^1.3.0"
- micromatch "^4.0.2"
- picomatch "^2.2.1"
+ micromatch "^4.0.4"
fast-json-stable-stringify@^2.0.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
fast-levenshtein@^2.0.6:
version "2.0.6"
- resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
-fast-safe-stringify@^2.0.4:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
- integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
-
fastq@^1.6.0:
- version "1.11.0"
- resolved "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz"
- integrity sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794"
+ integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==
dependencies:
reusify "^1.0.4"
-fd-slicer@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e"
- integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
- dependencies:
- pend "~1.2.0"
-
-fecha@^2.3.3:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
- integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
-
-fecha@^4.2.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce"
- integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==
-
-figures@^1.3.5:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
- integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
- dependencies:
- escape-string-regexp "^1.0.5"
- object-assign "^4.1.0"
-
figures@^3.0.0:
version "3.2.0"
- resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
dependencies:
escape-string-regexp "^1.0.5"
file-entry-cache@^6.0.1:
version "6.0.1"
- resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
dependencies:
flat-cache "^3.0.4"
-file-uri-to-path@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
- integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
-
-filelist@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.2.tgz#80202f21462d4d1c2e214119b1807c1bc0380e5b"
- integrity sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==
- dependencies:
- minimatch "^3.0.4"
-
-filename-regex@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
- integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=
-
-fill-range@^2.1.0:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565"
- integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==
- dependencies:
- is-number "^2.1.0"
- isobject "^2.0.0"
- randomatic "^3.0.0"
- repeat-element "^1.1.2"
- repeat-string "^1.5.2"
-
-fill-range@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
- integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
- dependencies:
- extend-shallow "^2.0.1"
- is-number "^3.0.0"
- repeat-string "^1.6.1"
- to-regex-range "^2.1.0"
-
fill-range@^7.0.1:
version "7.0.1"
- resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"
-filled-array@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/filled-array/-/filled-array-1.1.0.tgz#c3c4f6c663b923459a9aa29912d2d031f1507f84"
- integrity sha1-w8T2xmO5I0WamqKZEtLQMfFQf4Q=
-
-finalhandler@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
- integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- on-finished "~2.3.0"
- parseurl "~1.3.3"
- statuses "~1.5.0"
- unpipe "~1.0.0"
-
-find-port@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/find-port/-/find-port-1.0.1.tgz#db084a6cbf99564d99869ae79fbdecf66e8a185c"
- integrity sha1-2whKbL+ZVk2Zhprnn73s9m6KGFw=
- dependencies:
- async "~0.2.9"
-
-find-replace@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
- integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
- dependencies:
- array-back "^3.0.1"
-
-find-up@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
- integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
- dependencies:
- path-exists "^2.0.0"
- pinkie-promise "^2.0.0"
-
find-up@^2.0.0, find-up@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
dependencies:
locate-path "^2.0.0"
-find-up@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
- integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
- dependencies:
- locate-path "^3.0.0"
-
find-up@^4.1.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
dependencies:
locate-path "^5.0.0"
path-exists "^4.0.0"
-findup-sync@^0.4.2:
- version "0.4.3"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12"
- integrity sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=
- dependencies:
- detect-file "^0.1.0"
- is-glob "^2.0.1"
- micromatch "^2.3.7"
- resolve-dir "^0.1.0"
-
-findup-sync@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
- integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=
- dependencies:
- detect-file "^1.0.0"
- is-glob "^3.1.0"
- micromatch "^3.0.4"
- resolve-dir "^1.0.1"
-
-first-chunk-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
- integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=
-
-first-chunk-stream@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70"
- integrity sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=
- dependencies:
- readable-stream "^2.0.2"
-
flat-cache@^3.0.4:
version "3.0.4"
- resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
dependencies:
flatted "^3.1.0"
rimraf "^3.0.2"
flatted@^3.1.0:
- version "3.1.1"
- resolved "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz"
- integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==
-
-fn.name@1.x.x:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
- integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
-
-follow-redirects@^1.0.0, follow-redirects@^1.10.0:
- version "1.13.3"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
- integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==
-
-for-in@^1.0.1, for-in@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
- integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
-
-for-own@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce"
- integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=
- dependencies:
- for-in "^1.0.1"
-
-forever-agent@~0.6.1:
- version "0.6.1"
- resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
- integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
-
-fork-stream@^0.0.4:
- version "0.0.4"
- resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70"
- integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=
-
-form-data@*:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
- integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.8"
- mime-types "^2.1.12"
-
-form-data@~2.3.2:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
- integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
- dependencies:
- asynckit "^0.4.0"
- combined-stream "^1.0.6"
- mime-types "^2.1.12"
-
-formatio@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
- integrity sha1-87IWfZBoxGmKjVH092CjmlTYGOs=
- dependencies:
- samsam "1.x"
-
-forwarded@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
- integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
-
-fragment-cache@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
- integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
- dependencies:
- map-cache "^0.2.2"
-
-freeport@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/freeport/-/freeport-1.0.5.tgz#255e8ab84170c33ba85d990e821ae5f4a1a9bc5d"
- integrity sha1-JV6KuEFwwzuoXZkOghrl9KGpvF0=
-
-fresh@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
- integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-
-fs-constants@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
- integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
-
-fs-exists-sync@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add"
- integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0=
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561"
+ integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==
fs.realpath@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-fsevents@^1.0.0:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38"
- integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==
- dependencies:
- bindings "^1.5.0"
- nan "^2.12.1"
-
-fsevents@~2.3.1:
+fsevents@~2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
function-bind@^1.1.1:
version "1.1.1"
- resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
functional-red-black-tree@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
-gensync@^1.0.0-beta.2:
- version "1.0.0-beta.2"
- resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
- integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-
-get-intrinsic@^1.0.2, get-intrinsic@^1.1.1:
+get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
version "1.1.1"
- resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
-get-stdin@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
- integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
-
-get-stream@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
- integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
-
-get-stream@^4.0.0, get-stream@^4.1.0:
+get-stream@^4.1.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
-get-stream@^5.0.0, get-stream@^5.1.0:
+get-stream@^5.1.0:
version "5.2.0"
- resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
dependencies:
pump "^3.0.0"
get-stream@^6.0.0:
- version "6.0.0"
- resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz"
- integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
-get-value@^2.0.3, get-value@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
- integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
-
-getpass@^0.1.1:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
- integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
- dependencies:
- assert-plus "^1.0.0"
-
-gh-got@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-5.0.0.tgz#ee95be37106fd8748a96f8d1db4baea89e1bfa8a"
- integrity sha1-7pW+NxBv2HSKlvjR20uuqJ4b+oo=
- dependencies:
- got "^6.2.0"
- is-plain-obj "^1.1.0"
-
-gh-got@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/gh-got/-/gh-got-6.0.0.tgz#d74353004c6ec466647520a10bd46f7299d268d0"
- integrity sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==
- dependencies:
- got "^7.0.0"
- is-plain-obj "^1.1.0"
-
-github-username@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/github-username/-/github-username-3.0.0.tgz#0a772219b3130743429f2456d0bdd3db55dce7b1"
- integrity sha1-CnciGbMTB0NCnyRW0L3T21Xc57E=
- dependencies:
- gh-got "^5.0.0"
-
-github-username@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/github-username/-/github-username-4.1.0.tgz#cbe280041883206da4212ae9e4b5f169c30bf417"
- integrity sha1-y+KABBiDIG2kISrp5LXxacML9Bc=
- dependencies:
- gh-got "^6.0.0"
-
-glob-base@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4"
- integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=
- dependencies:
- glob-parent "^2.0.0"
- is-glob "^2.0.0"
-
-glob-parent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28"
- integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=
- dependencies:
- is-glob "^2.0.0"
-
-glob-parent@^3.0.0, glob-parent@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
- integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
- dependencies:
- is-glob "^3.1.0"
- path-dirname "^1.0.0"
-
-glob-parent@^5.0.0, glob-parent@^5.1.0:
+glob-parent@^5.1.2:
version "5.1.2"
- resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
dependencies:
is-glob "^4.0.1"
-glob-stream@^5.3.2:
- version "5.3.5"
- resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22"
- integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=
- dependencies:
- extend "^3.0.0"
- glob "^5.0.3"
- glob-parent "^3.0.0"
- micromatch "^2.3.7"
- ordered-read-streams "^0.3.0"
- through2 "^0.6.0"
- to-absolute-glob "^0.1.1"
- unique-stream "^2.0.2"
-
-glob-to-regexp@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
- integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
-
-glob@^5.0.3:
- version "5.0.15"
- resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
- integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^6.0.1:
- version "6.0.4"
- resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
- integrity sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
- version "7.1.6"
- resolved "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
+glob@^7.1.3:
+ version "7.1.7"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
+ integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -4968,94 +1286,20 @@
once "^1.3.0"
path-is-absolute "^1.0.0"
-global-dirs@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
- integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
- dependencies:
- ini "^1.3.4"
-
global-dirs@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686"
integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==
dependencies:
ini "2.0.0"
-global-modules@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d"
- integrity sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=
- dependencies:
- global-prefix "^0.1.4"
- is-windows "^0.2.0"
-
-global-modules@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
- integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
- dependencies:
- global-prefix "^1.0.1"
- is-windows "^1.0.1"
- resolve-dir "^1.0.0"
-
-global-prefix@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f"
- integrity sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=
- dependencies:
- homedir-polyfill "^1.0.0"
- ini "^1.3.4"
- is-windows "^0.2.0"
- which "^1.2.12"
-
-global-prefix@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
- integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
- dependencies:
- expand-tilde "^2.0.2"
- homedir-polyfill "^1.0.1"
- ini "^1.3.4"
- is-windows "^1.0.1"
- which "^1.2.14"
-
-globals@^11.1.0:
- version "11.12.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
- integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-globals@^12.1.0:
- version "12.4.0"
- resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz"
- integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
- dependencies:
- type-fest "^0.8.1"
-
-globals@^13.6.0:
- version "13.8.0"
- resolved "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz"
- integrity sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==
+globals@^13.6.0, globals@^13.9.0:
+ version "13.11.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7"
+ integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==
dependencies:
type-fest "^0.20.2"
-globals@^9.18.0:
- version "9.18.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
- integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
-
-globby@^11.0.1:
- version "11.0.3"
- resolved "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz"
- integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.1.1"
- ignore "^5.1.4"
- merge2 "^1.3.0"
- slash "^3.0.0"
-
globby@^11.0.3:
version "11.0.4"
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
@@ -5068,134 +1312,9 @@
merge2 "^1.3.0"
slash "^3.0.0"
-globby@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8"
- integrity sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=
- dependencies:
- array-union "^1.0.1"
- arrify "^1.0.0"
- glob "^6.0.1"
- object-assign "^4.0.1"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-globby@^6.1.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
- integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
- dependencies:
- array-union "^1.0.1"
- glob "^7.0.3"
- object-assign "^4.0.1"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-globby@^8.0.1:
- version "8.0.2"
- resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.2.tgz#5697619ccd95c5275dbb2d6faa42087c1a941d8d"
- integrity sha512-yTzMmKygLp8RUpG1Ymu2VXPSJQZjNAZPD4ywgYEaG7e4tBJeUQBO8OpXrf1RCNcEs5alsoJYPAMiIHP0cmeC7w==
- dependencies:
- array-union "^1.0.1"
- dir-glob "2.0.0"
- fast-glob "^2.0.2"
- glob "^7.1.2"
- ignore "^3.3.5"
- pify "^3.0.0"
- slash "^1.0.0"
-
-globby@^9.2.0:
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
- integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
- dependencies:
- "@types/glob" "^7.1.1"
- array-union "^1.0.2"
- dir-glob "^2.2.2"
- fast-glob "^2.2.6"
- glob "^7.1.3"
- ignore "^4.0.3"
- pify "^4.0.1"
- slash "^2.0.0"
-
-got@^11.8.0:
- version "11.8.2"
- resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
- integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==
- dependencies:
- "@sindresorhus/is" "^4.0.0"
- "@szmarczak/http-timer" "^4.0.5"
- "@types/cacheable-request" "^6.0.1"
- "@types/responselike" "^1.0.0"
- cacheable-lookup "^5.0.3"
- cacheable-request "^7.0.1"
- decompress-response "^6.0.0"
- http2-wrapper "^1.0.0-beta.5.2"
- lowercase-keys "^2.0.0"
- p-cancelable "^2.0.0"
- responselike "^2.0.0"
-
-got@^5.0.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/got/-/got-5.7.1.tgz#5f81635a61e4a6589f180569ea4e381680a51f35"
- integrity sha1-X4FjWmHkplifGAVp6k44FoClHzU=
- dependencies:
- create-error-class "^3.0.1"
- duplexer2 "^0.1.4"
- is-redirect "^1.0.0"
- is-retry-allowed "^1.0.0"
- is-stream "^1.0.0"
- lowercase-keys "^1.0.0"
- node-status-codes "^1.0.0"
- object-assign "^4.0.1"
- parse-json "^2.1.0"
- pinkie-promise "^2.0.0"
- read-all-stream "^3.0.0"
- readable-stream "^2.0.5"
- timed-out "^3.0.0"
- unzip-response "^1.0.2"
- url-parse-lax "^1.0.0"
-
-got@^6.2.0, got@^6.7.1:
- version "6.7.1"
- resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
- integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
- dependencies:
- create-error-class "^3.0.0"
- duplexer3 "^0.1.4"
- get-stream "^3.0.0"
- is-redirect "^1.0.0"
- is-retry-allowed "^1.0.0"
- is-stream "^1.0.0"
- lowercase-keys "^1.0.0"
- safe-buffer "^5.0.1"
- timed-out "^4.0.0"
- unzip-response "^2.0.1"
- url-parse-lax "^1.0.0"
-
-got@^7.0.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a"
- integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==
- dependencies:
- decompress-response "^3.2.0"
- duplexer3 "^0.1.4"
- get-stream "^3.0.0"
- is-plain-obj "^1.1.0"
- is-retry-allowed "^1.0.0"
- is-stream "^1.0.0"
- isurl "^1.0.0-alpha5"
- lowercase-keys "^1.0.0"
- p-cancelable "^0.3.0"
- p-timeout "^1.1.1"
- safe-buffer "^5.0.1"
- timed-out "^4.0.0"
- url-parse-lax "^1.0.0"
- url-to-options "^1.0.1"
-
got@^9.6.0:
version "9.6.0"
- resolved "https://registry.npmjs.org/got/-/got-9.6.0.tgz"
+ resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
dependencies:
"@sindresorhus/is" "^0.14.0"
@@ -5210,24 +1329,10 @@
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
-graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.2.0:
- version "4.2.6"
- resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz"
- integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
-
-grouped-queue@^0.3.0:
- version "0.3.3"
- resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-0.3.3.tgz#c167d2a5319c5a0e0964ef6a25b7c2df8996c85c"
- integrity sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=
- dependencies:
- lodash "^4.17.2"
-
-grouped-queue@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/grouped-queue/-/grouped-queue-1.1.0.tgz#63e3f9ca90af952269d1d40879e41221eacc74cb"
- integrity sha512-rZOFKfCqLhsu5VqjBjEWiwrYqJR07KxIkH4mLZlNlGDfntbb4FbMyGFP14TlvRPrU9S3Hnn/sgxbC5ZeN0no3Q==
- dependencies:
- lodash "^4.17.15"
+graceful-fs@^4.1.2:
+ version "4.2.8"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
+ integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
gts@^3.1.0:
version "3.1.0"
@@ -5251,214 +1356,62 @@
update-notifier "^5.0.0"
write-file-atomic "^3.0.3"
-gulp-if@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629"
- integrity sha1-pJe351cwBQQcqivIt92jyARE1ik=
- dependencies:
- gulp-match "^1.0.3"
- ternary-stream "^2.0.1"
- through2 "^2.0.1"
-
-gulp-match@^1.0.3:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f"
- integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ==
- dependencies:
- minimatch "^3.0.3"
-
-gulp-sourcemaps@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
- integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=
- dependencies:
- convert-source-map "^1.1.1"
- graceful-fs "^4.1.2"
- strip-bom "^2.0.0"
- through2 "^2.0.0"
- vinyl "^1.0.0"
-
-gunzip-maybe@^1.3.1:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac"
- integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==
- dependencies:
- browserify-zlib "^0.1.4"
- is-deflate "^1.0.0"
- is-gzip "^1.0.0"
- peek-stream "^1.1.0"
- pumpify "^1.3.3"
- through2 "^2.0.3"
-
-handle-thing@^1.2.5:
- version "1.2.5"
- resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
- integrity sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=
-
-har-schema@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
- integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
-
-har-validator@~5.1.0, har-validator@~5.1.3:
- version "5.1.5"
- resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
- integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
- dependencies:
- ajv "^6.12.3"
- har-schema "^2.0.0"
-
hard-rejection@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
-has-ansi@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
- integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
- dependencies:
- ansi-regex "^2.0.0"
-
has-bigints@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
-has-binary2@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
- integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==
- dependencies:
- isarray "2.0.1"
-
-has-color@~0.1.0:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f"
- integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=
-
-has-cors@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
- integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
-
has-flag@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
has-flag@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-has-symbol-support-x@^1.4.1:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455"
- integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
-
has-symbols@^1.0.1, has-symbols@^1.0.2:
version "1.0.2"
- resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
-has-to-string-tag-x@^1.2.0:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d"
- integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==
- dependencies:
- has-symbol-support-x "^1.4.1"
-
-has-value@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
- integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
- dependencies:
- get-value "^2.0.3"
- has-values "^0.1.4"
- isobject "^2.0.0"
-
-has-value@^1.0.0:
+has-tostringtag@^1.0.0:
version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
- integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25"
+ integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==
dependencies:
- get-value "^2.0.6"
- has-values "^1.0.0"
- isobject "^3.0.0"
-
-has-values@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
- integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
-
-has-values@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
- integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
- dependencies:
- is-number "^3.0.0"
- kind-of "^4.0.0"
+ has-symbols "^1.0.2"
has-yarn@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.3:
version "1.0.3"
- resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
dependencies:
function-bind "^1.1.1"
-he@1.2.x:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
- integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
-
-homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
- integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
- dependencies:
- parse-passwd "^1.0.0"
-
hosted-git-info@^2.1.4:
version "2.8.9"
- resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
hosted-git-info@^4.0.1:
version "4.0.2"
- resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961"
integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==
dependencies:
lru-cache "^6.0.0"
-hpack.js@^2.1.6:
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
- integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
- dependencies:
- inherits "^2.0.1"
- obuf "^1.0.0"
- readable-stream "^2.0.1"
- wbuf "^1.1.0"
-
-html-minifier@^3.5.10:
- version "3.5.21"
- resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
- integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
- dependencies:
- camel-case "3.0.x"
- clean-css "4.2.x"
- commander "2.17.x"
- he "1.2.x"
- param-case "2.1.x"
- relateurl "0.2.x"
- uglify-js "3.4.x"
-
htmlparser2@^3.9.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
@@ -5473,7 +1426,7 @@
htmlparser2@^6.0.1:
version "6.1.0"
- resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
dependencies:
domelementtype "^2.0.1"
@@ -5483,138 +1436,34 @@
http-cache-semantics@^4.0.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
-http-deceiver@^1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
- integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
-
-http-errors@1.7.2:
- version "1.7.2"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
- integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-errors@~1.6.2:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
- integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
- dependencies:
- depd "~1.1.2"
- inherits "2.0.3"
- setprototypeof "1.1.0"
- statuses ">= 1.4.0 < 2"
-
-http-errors@~1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
- integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
- dependencies:
- depd "~1.1.2"
- inherits "2.0.4"
- setprototypeof "1.1.1"
- statuses ">= 1.5.0 < 2"
- toidentifier "1.0.0"
-
-http-proxy-middleware@^0.17.2:
- version "0.17.4"
- resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833"
- integrity sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=
- dependencies:
- http-proxy "^1.16.2"
- is-glob "^3.1.0"
- lodash "^4.17.2"
- micromatch "^2.3.11"
-
-http-proxy@^1.16.2:
- version "1.18.1"
- resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
- integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
- dependencies:
- eventemitter3 "^4.0.0"
- follow-redirects "^1.0.0"
- requires-port "^1.0.0"
-
-http-signature@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
- integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
- dependencies:
- assert-plus "^1.0.0"
- jsprim "^1.2.2"
- sshpk "^1.7.0"
-
-http2-wrapper@^1.0.0-beta.5.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
- integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
- dependencies:
- quick-lru "^5.1.1"
- resolve-alpn "^1.0.0"
-
-https-proxy-agent@^2.2.1:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b"
- integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==
- dependencies:
- agent-base "^4.3.0"
- debug "^3.1.0"
-
-https-proxy-agent@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
- integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==
- dependencies:
- agent-base "6"
- debug "4"
-
-human-signals@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
- integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
-
human-signals@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
-iconv-lite@0.4.24, iconv-lite@^0.4.24:
+iconv-lite@^0.4.24:
version "0.4.24"
- resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
-ieee754@^1.1.13:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
- integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-
-ignore@^3.3.5:
- version "3.3.10"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
- integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
-
-ignore@^4.0.3, ignore@^4.0.6:
+ignore@^4.0.6:
version "4.0.6"
- resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
ignore@^5.1.1, ignore@^5.1.4:
version "5.1.8"
- resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
- resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
@@ -5622,87 +1471,45 @@
import-lazy@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
imurmurhash@^0.1.4:
version "0.1.4"
- resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-indent-string@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
- integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
- dependencies:
- repeating "^2.0.0"
-
indent-string@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-indent@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/indent/-/indent-0.0.2.tgz#8c79f080190559b687034b84c7aefa97d5a911d9"
- integrity sha1-jHnwgBkFWbaHA0uEx676l9WpEdk=
-
-indexof@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
- integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
-
inflight@^1.0.4:
version "1.0.6"
- resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
dependencies:
once "^1.3.0"
wrappy "1"
-inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@^2.0.1, inherits@^2.0.3:
version "2.0.4"
- resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-inherits@2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
ini@2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
-ini@^1.3.4, ini@~1.3.0:
+ini@~1.3.0:
version "1.3.8"
- resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
-inquirer@^1.0.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-1.2.3.tgz#4dec6f32f37ef7bb0b2ed3f1d1a5c3f545074918"
- integrity sha1-TexvMvN+97sLLtPx0aXD9UUHSRg=
- dependencies:
- ansi-escapes "^1.1.0"
- chalk "^1.0.0"
- cli-cursor "^1.0.1"
- cli-width "^2.0.0"
- external-editor "^1.1.0"
- figures "^1.3.5"
- lodash "^4.3.0"
- mute-stream "0.0.6"
- pinkie-promise "^2.0.0"
- run-async "^2.2.0"
- rx "^4.1.0"
- string-width "^1.0.1"
- strip-ansi "^3.0.0"
- through "^2.3.6"
-
-inquirer@^7.1.0, inquirer@^7.3.3:
+inquirer@^7.3.3:
version "7.3.3"
- resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
@@ -5719,237 +1526,86 @@
strip-ansi "^6.0.0"
through "^2.3.6"
-interpret@^1.0.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
- integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
-
-intersect@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/intersect/-/intersect-1.0.1.tgz#332650e10854d8c0ac58c192bdc27a8bf7e7a30c"
- integrity sha1-MyZQ4QhU2MCsWMGSvcJ6i/fnoww=
-
-invariant@^2.2.2:
- version "2.2.4"
- resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
- integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+internal-slot@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
+ integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==
dependencies:
- loose-envify "^1.0.0"
-
-ipaddr.js@1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
- integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
-
-is-accessor-descriptor@^0.1.6:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
- integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
- dependencies:
- kind-of "^3.0.2"
-
-is-accessor-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
- integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
- dependencies:
- kind-of "^6.0.0"
+ get-intrinsic "^1.1.0"
+ has "^1.0.3"
+ side-channel "^1.0.4"
is-arrayish@^0.2.1:
version "0.2.1"
- resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
-is-arrayish@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
- integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
-
is-bigint@^1.0.1:
- version "1.0.1"
- resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz"
- integrity sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==
-
-is-binary-path@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
- integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3"
+ integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==
dependencies:
- binary-extensions "^1.0.0"
+ has-bigints "^1.0.1"
is-boolean-object@^1.1.0:
- version "1.1.0"
- resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz"
- integrity sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719"
+ integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==
dependencies:
- call-bind "^1.0.0"
-
-is-buffer@^1.1.5, is-buffer@~1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
- integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
is-callable@^1.1.4, is-callable@^1.2.3:
- version "1.2.3"
- resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz"
- integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==
-
-is-ci@^1.0.10:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
- integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
- dependencies:
- ci-info "^1.5.0"
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
+ integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
is-ci@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
dependencies:
ci-info "^2.0.0"
-is-core-module@^2.2.0:
- version "2.2.0"
- resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz"
- integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
+is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.6.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
+ integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
dependencies:
has "^1.0.3"
-is-data-descriptor@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
- integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
- dependencies:
- kind-of "^3.0.2"
-
-is-data-descriptor@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
- integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
- dependencies:
- kind-of "^6.0.0"
-
is-date-object@^1.0.1:
- version "1.0.2"
- resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz"
- integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
-
-is-deflate@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14"
- integrity sha1-yGKQHDwWH7CdrHzcfnhPgOmPLxQ=
-
-is-descriptor@^0.1.0:
- version "0.1.6"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
- integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
+ integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==
dependencies:
- is-accessor-descriptor "^0.1.6"
- is-data-descriptor "^0.1.4"
- kind-of "^5.0.0"
+ has-tostringtag "^1.0.0"
-is-descriptor@^1.0.0, is-descriptor@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
- integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
- dependencies:
- is-accessor-descriptor "^1.0.0"
- is-data-descriptor "^1.0.0"
- kind-of "^6.0.2"
-
-is-dotfile@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
- integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=
-
-is-equal-shallow@^0.1.3:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534"
- integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=
- dependencies:
- is-primitive "^2.0.0"
-
-is-extendable@^0.1.0, is-extendable@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
- integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
-
-is-extendable@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
- integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
- dependencies:
- is-plain-object "^2.0.4"
-
-is-extglob@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
- integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=
-
-is-extglob@^2.1.0, is-extglob@^2.1.1:
+is-extglob@^2.1.1:
version "2.1.1"
- resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
-is-finite@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3"
- integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==
-
-is-fullwidth-code-point@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
- integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
- dependencies:
- number-is-nan "^1.0.0"
-
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-is-glob@^2.0.0, is-glob@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863"
- integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=
- dependencies:
- is-extglob "^1.0.0"
-
-is-glob@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
- integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
- dependencies:
- is-extglob "^2.1.0"
-
is-glob@^4.0.0, is-glob@^4.0.1:
version "4.0.1"
- resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
is-extglob "^2.1.1"
-is-gzip@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83"
- integrity sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=
-
-is-installed-globally@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
- integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
- dependencies:
- global-dirs "^0.1.0"
- is-path-inside "^1.0.0"
-
is-installed-globally@^0.4.0:
version "0.4.0"
- resolved "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520"
integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==
dependencies:
global-dirs "^3.0.0"
@@ -5957,325 +1613,106 @@
is-negative-zero@^2.0.1:
version "2.0.1"
- resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
-is-npm@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
- integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
-
is-npm@^5.0.0:
version "5.0.0"
- resolved "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8"
integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==
is-number-object@^1.0.4:
- version "1.0.4"
- resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz"
- integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==
-
-is-number@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f"
- integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0"
+ integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==
dependencies:
- kind-of "^3.0.2"
-
-is-number@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
- integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
- dependencies:
- kind-of "^3.0.2"
-
-is-number@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff"
- integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==
+ has-tostringtag "^1.0.0"
is-number@^7.0.0:
version "7.0.0"
- resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-is-obj@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
- integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
-
is-obj@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
-is-object@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf"
- integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==
-
-is-path-cwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
- integrity sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=
-
-is-path-in-cwd@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52"
- integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==
- dependencies:
- is-path-inside "^1.0.0"
-
-is-path-inside@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
- integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
- dependencies:
- path-is-inside "^1.0.1"
-
is-path-inside@^3.0.2:
version "3.0.3"
- resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
-is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
+is-plain-obj@^1.1.0:
version "1.1.0"
- resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
-is-plain-object@^2.0.3, is-plain-object@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
- integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
- dependencies:
- isobject "^3.0.1"
-
-is-plain-object@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
- integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
-
-is-posix-bracket@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
- integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=
-
-is-potential-custom-element-name@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
- integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
-
-is-primitive@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
- integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU=
-
-is-redirect@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
- integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
-
-is-regex@^1.1.2:
- version "1.1.2"
- resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz"
- integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==
+is-regex@^1.1.3:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
+ integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
dependencies:
call-bind "^1.0.2"
- has-symbols "^1.0.1"
-
-is-retry-allowed@^1.0.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
- integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
-
-is-scoped@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-scoped/-/is-scoped-1.0.0.tgz#449ca98299e713038256289ecb2b540dc437cb30"
- integrity sha1-RJypgpnnEwOCViieyytUDcQ3yzA=
- dependencies:
- scoped-regex "^1.0.0"
-
-is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
- integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+ has-tostringtag "^1.0.0"
is-stream@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz"
- integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
-is-string@^1.0.5:
- version "1.0.5"
- resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz"
- integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
+is-string@^1.0.5, is-string@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
+ integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
+ dependencies:
+ has-tostringtag "^1.0.0"
is-symbol@^1.0.2, is-symbol@^1.0.3:
- version "1.0.3"
- resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz"
- integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c"
+ integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==
dependencies:
- has-symbols "^1.0.1"
+ has-symbols "^1.0.2"
-is-typedarray@^1.0.0, is-typedarray@~1.0.0:
+is-typedarray@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-is-utf8@^0.2.0, is-utf8@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
- integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
-
-is-valid-glob@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe"
- integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=
-
-is-windows@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
- integrity sha1-3hqm1j6indJIc3tp8f+LgALSEIw=
-
-is-windows@^1.0.1, is-windows@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
- integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
-
is-yarn-global@^0.3.0:
version "0.3.0"
- resolved "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
-isarray@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
- integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
-
-isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-
-isarray@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
- integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
-
-isbinaryfile@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
- integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==
- dependencies:
- buffer-alloc "^1.2.0"
-
-isbinaryfile@^4.0.0:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.6.tgz#edcb62b224e2b4710830b67498c8e4e5a4d2610b"
- integrity sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==
-
isexe@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-isobject@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
- integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
- dependencies:
- isarray "1.0.0"
-
-isobject@^3.0.0, isobject@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
- integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-
-isstream@~0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
- integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-
-istextorbinary@^2.2.1, istextorbinary@^2.5.1:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.6.0.tgz#60776315fb0fa3999add276c02c69557b9ca28ab"
- integrity sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA==
- dependencies:
- binaryextensions "^2.1.2"
- editions "^2.2.0"
- textextensions "^2.5.0"
-
-isurl@^1.0.0-alpha5:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67"
- integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==
- dependencies:
- has-to-string-tag-x "^1.2.0"
- is-object "^1.0.1"
-
-jake@^10.6.1:
- version "10.8.2"
- resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b"
- integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==
- dependencies:
- async "0.9.x"
- chalk "^2.4.2"
- filelist "^1.0.1"
- minimatch "^3.0.4"
-
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+js-tokens@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-tokens@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
- integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
js-yaml@^3.13.1:
version "3.14.1"
- resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
-jsbn@~0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
- integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
-
jsdoctypeparser@^9.0.0:
version "9.0.0"
- resolved "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-9.0.0.tgz#8c97e2fb69315eb274b0f01377eaa5c940bd7b26"
integrity sha512-jrTA2jJIL6/DAEILBEh2/w9QxCuwmvNXIry39Ay/HVfhE3o2yVV0U44blYkqdHA/OKloJEqvJy0xU+GSdE2SIw==
-jsesc@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
- integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
-
-jsesc@^2.5.1:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
- integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-jsesc@~0.5.0:
- version "0.5.0"
- resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
- integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
-
json-buffer@3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
-json-buffer@3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
- integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
-
json-parse-better-errors@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@@ -6283,168 +1720,60 @@
json-parse-even-better-errors@^2.3.0:
version "2.3.1"
- resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json-schema-traverse@^0.4.1:
version "0.4.1"
- resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
json-schema-traverse@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
-json-schema@0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
- integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
-
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-json-stringify-safe@~5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
- integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-
json5@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
dependencies:
minimist "^1.2.0"
-json5@^2.1.2, json5@^2.1.3:
+json5@^2.1.3:
version "2.2.0"
- resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
-jsonparse@^1.2.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
- integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
-
-jsonschema@^1.1.0, jsonschema@^1.1.1:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2"
- integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw==
-
-jsprim@^1.2.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
- integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
- dependencies:
- assert-plus "1.0.0"
- extsprintf "1.3.0"
- json-schema "0.2.3"
- verror "1.10.0"
-
keyv@^3.0.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
-keyv@^4.0.0:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
- integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
- dependencies:
- json-buffer "3.0.1"
-
-kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
- integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
- integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
- dependencies:
- is-buffer "^1.1.5"
-
-kind-of@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
- integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
-
-kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
+kind-of@^6.0.3:
version "6.0.3"
- resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-kuler@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
- integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
-
-latest-version@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-2.0.0.tgz#56f8d6139620847b8017f8f1f4d78e211324168b"
- integrity sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=
- dependencies:
- package-json "^2.0.0"
-
-latest-version@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
- integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
- dependencies:
- package-json "^4.0.0"
-
latest-version@^5.1.0:
version "5.1.0"
- resolved "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
dependencies:
package-json "^6.3.0"
-launchpad@^0.7.0:
- version "0.7.5"
- resolved "https://registry.yarnpkg.com/launchpad/-/launchpad-0.7.5.tgz#a16950c937572f10ef01c9be945a96f7aef8e427"
- integrity sha512-gsYFgT8XKL3X2XZHPPPrgwM0JqeQwGpSWnzg7EYadBY3MirbQrTVq6L4fm6l7UE2T+7gnfuhiGkKr/xxuU/fdw==
- dependencies:
- async "^2.0.1"
- browserstack "^1.2.0"
- debug "^2.2.0"
- mkdirp "^0.5.1"
- plist "^2.0.1"
- q "^1.4.1"
- rimraf "^3.0.0"
- underscore "^1.8.3"
-
-lazy-cache@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
- integrity sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=
- dependencies:
- set-getter "^0.1.0"
-
-lazy-req@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/lazy-req/-/lazy-req-1.1.0.tgz#bdaebead30f8d824039ce0ce149d4daa07ba1fac"
- integrity sha1-va6+rTD42CQDnODOFJ1Nqge6H6w=
-
-lazystream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
- integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
- dependencies:
- readable-stream "^2.0.5"
-
levn@^0.4.1:
version "0.4.1"
- resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
dependencies:
prelude-ls "^1.2.1"
@@ -6452,30 +1781,9 @@
lines-and-columns@^1.1.6:
version "1.1.6"
- resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
-load-json-file@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
- integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
-
-load-json-file@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz"
- integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- strip-bom "^3.0.0"
-
load-json-file@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
@@ -6488,381 +1796,81 @@
locate-path@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
dependencies:
p-locate "^2.0.0"
path-exists "^3.0.0"
-locate-path@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
- integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
- dependencies:
- p-locate "^3.0.0"
- path-exists "^3.0.0"
-
locate-path@^5.0.0:
version "5.0.0"
- resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
dependencies:
p-locate "^4.1.0"
-lodash._reinterpolate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
- integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
-
-lodash.camelcase@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
- integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
-
lodash.clonedeep@^4.5.0:
version "4.5.0"
- resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
+ resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
-lodash.defaults@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
- integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
-
-lodash.difference@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
- integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
-
-lodash.flatten@^4.4.0:
- version "4.4.0"
- resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz"
- integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
-
-lodash.get@^4.4.2:
- version "4.4.2"
- resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
- integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
-
-lodash.isequal@^4.0.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
- integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
-
-lodash.mapvalues@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
- integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
-
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-lodash.padend@^4.6.1:
- version "4.6.1"
- resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e"
- integrity sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4=
-
-lodash.set@^4.3.2:
- version "4.3.2"
- resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23"
- integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=
-
-lodash.sortby@^4.7.0:
- version "4.7.0"
- resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
- integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
-
-lodash.template@^4.4.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab"
- integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==
- dependencies:
- lodash._reinterpolate "^3.0.0"
- lodash.templatesettings "^4.0.0"
-
-lodash.templatesettings@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33"
- integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==
- dependencies:
- lodash._reinterpolate "^3.0.0"
-
lodash.truncate@^4.4.2:
version "4.4.2"
- resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz"
+ resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
-lodash.union@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
- integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
-
-lodash.uniq@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
- integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
-
-lodash@^3.0.0, lodash@^3.10.1:
- version "3.10.1"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
- integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
-
-lodash@^4.0.0, lodash@^4.11.1, lodash@^4.15.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.3.0:
+lodash@4.17.21, lodash@^4.15.0, lodash@^4.17.19, lodash@^4.17.21:
version "4.17.21"
- resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-log-symbols@^1.0.0, log-symbols@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
- integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=
- dependencies:
- chalk "^1.0.0"
-
-log-symbols@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
- integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
- dependencies:
- chalk "^2.0.1"
-
-logform@^1.9.1:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/logform/-/logform-1.10.0.tgz#c9d5598714c92b546e23f4e78147c40f1e02012e"
- integrity sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==
- dependencies:
- colors "^1.2.1"
- fast-safe-stringify "^2.0.4"
- fecha "^2.3.3"
- ms "^2.1.1"
- triple-beam "^1.2.0"
-
-logform@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2"
- integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==
- dependencies:
- colors "^1.2.1"
- fast-safe-stringify "^2.0.4"
- fecha "^4.2.0"
- ms "^2.1.1"
- triple-beam "^1.3.0"
-
-lolex@^1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6"
- integrity sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=
-
long@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
-loose-envify@^1.0.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
- integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
- dependencies:
- js-tokens "^3.0.0 || ^4.0.0"
-
-loud-rejection@^1.0.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
- integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
- dependencies:
- currently-unhandled "^0.4.1"
- signal-exit "^3.0.0"
-
-lower-case@^1.1.1:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
- integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
-
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowercase-keys@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
-lru-cache@^4.0.1, lru-cache@^4.0.2:
- version "4.1.5"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
- integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
- dependencies:
- pseudomap "^1.0.2"
- yallist "^2.1.2"
-
lru-cache@^6.0.0:
version "6.0.0"
- resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
dependencies:
yallist "^4.0.0"
-macos-release@^2.2.0:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.4.1.tgz#64033d0ec6a5e6375155a74b1a1eba8e509820ac"
- integrity sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==
-
-magic-string@^0.22.4:
- version "0.22.5"
- resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.22.5.tgz#8e9cf5afddf44385c1da5bc2a6a0dbd10b03657e"
- integrity sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==
- dependencies:
- vlq "^0.2.2"
-
-make-dir@^1.0.0, make-dir@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
- integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
- dependencies:
- pify "^3.0.0"
-
make-dir@^3.0.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
dependencies:
semver "^6.0.0"
-map-cache@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
- integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
-
-map-obj@^1.0.0, map-obj@^1.0.1:
+map-obj@^1.0.0:
version "1.0.1"
- resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
map-obj@^4.0.0:
version "4.2.1"
- resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7"
integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==
-map-visit@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
- integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
- dependencies:
- object-visit "^1.0.0"
-
-matcher@^1.1.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/matcher/-/matcher-1.1.1.tgz#51d8301e138f840982b338b116bb0c09af62c1c2"
- integrity sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==
- dependencies:
- escape-string-regexp "^1.0.4"
-
-math-random@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c"
- integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==
-
-md5@^2.2.1:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
- integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
- dependencies:
- charenc "0.0.2"
- crypt "0.0.2"
- is-buffer "~1.1.6"
-
-media-typer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
- integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
-
-mem-fs-editor@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-5.1.0.tgz#51972241640be8567680a04f7adaffe5fc603667"
- integrity sha512-2Yt2GCYEbcotYbIJagmow4gEtHDqzpq5XN94+yAx/NT5+bGqIjkXnm3KCUQfE6kRfScGp9IZknScoGRKu8L78w==
- dependencies:
- commondir "^1.0.1"
- deep-extend "^0.6.0"
- ejs "^2.5.9"
- glob "^7.0.3"
- globby "^8.0.1"
- isbinaryfile "^3.0.2"
- mkdirp "^0.5.0"
- multimatch "^2.0.0"
- rimraf "^2.2.8"
- through2 "^2.0.0"
- vinyl "^2.0.1"
-
-mem-fs-editor@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-6.0.0.tgz#d63607cf0a52fe6963fc376c6a7aa52db3edabab"
- integrity sha512-e0WfJAMm8Gv1mP5fEq/Blzy6Lt1VbLg7gNnZmZak7nhrBTibs+c6nQ4SKs/ZyJYHS1mFgDJeopsLAv7Ow0FMFg==
- dependencies:
- commondir "^1.0.1"
- deep-extend "^0.6.0"
- ejs "^2.6.1"
- glob "^7.1.4"
- globby "^9.2.0"
- isbinaryfile "^4.0.0"
- mkdirp "^0.5.0"
- multimatch "^4.0.0"
- rimraf "^2.6.3"
- through2 "^3.0.1"
- vinyl "^2.2.0"
-
-mem-fs-editor@^7.0.1:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/mem-fs-editor/-/mem-fs-editor-7.1.0.tgz#2a16f143228df87bf918874556723a7ee73bfe88"
- integrity sha512-BH6QEqCXSqGeX48V7zu+e3cMwHU7x640NB8Zk8VNvVZniz+p4FK60pMx/3yfkzo6miI6G3a8pH6z7FeuIzqrzA==
- dependencies:
- commondir "^1.0.1"
- deep-extend "^0.6.0"
- ejs "^3.1.5"
- glob "^7.1.4"
- globby "^9.2.0"
- isbinaryfile "^4.0.0"
- mkdirp "^1.0.0"
- multimatch "^4.0.0"
- rimraf "^3.0.0"
- through2 "^3.0.2"
- vinyl "^2.2.1"
-
-mem-fs@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/mem-fs/-/mem-fs-1.2.0.tgz#5f29b2d02a5875cd14cd836c388385892d556cde"
- integrity sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ==
- dependencies:
- through2 "^3.0.0"
- vinyl "^2.0.1"
- vinyl-file "^3.0.0"
-
-meow@^3.7.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
- integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
- dependencies:
- camelcase-keys "^2.0.0"
- decamelize "^1.1.2"
- loud-rejection "^1.0.0"
- map-obj "^1.0.1"
- minimist "^1.1.3"
- normalize-package-data "^2.3.4"
- object-assign "^4.0.1"
- read-pkg-up "^1.0.1"
- redent "^1.0.0"
- trim-newlines "^1.0.0"
-
meow@^9.0.0:
version "9.0.0"
- resolved "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364"
integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==
dependencies:
"@types/minimist" "^1.2.0"
@@ -6878,145 +1886,39 @@
type-fest "^0.18.0"
yargs-parser "^20.2.3"
-merge-descriptors@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
- integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
-
-merge-stream@^1.0.0, merge-stream@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
- integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=
- dependencies:
- readable-stream "^2.0.1"
-
merge-stream@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-merge2@^1.2.3, merge2@^1.3.0:
+merge2@^1.3.0:
version "1.4.1"
- resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-methods@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
- integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-
-micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7:
- version "2.3.11"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
- integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=
- dependencies:
- arr-diff "^2.0.0"
- array-unique "^0.2.1"
- braces "^1.8.2"
- expand-brackets "^0.1.4"
- extglob "^0.3.1"
- filename-regex "^2.0.0"
- is-extglob "^1.0.0"
- is-glob "^2.0.1"
- kind-of "^3.0.2"
- normalize-path "^2.0.1"
- object.omit "^2.0.0"
- parse-glob "^3.0.4"
- regex-cache "^0.4.2"
-
-micromatch@^3.0.4, micromatch@^3.1.10:
- version "3.1.10"
- resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
- integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- braces "^2.3.1"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- extglob "^2.0.4"
- fragment-cache "^0.2.1"
- kind-of "^6.0.2"
- nanomatch "^1.2.9"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.2"
-
-micromatch@^4.0.2:
- version "4.0.2"
- resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz"
- integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+micromatch@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9"
+ integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==
dependencies:
braces "^3.0.1"
- picomatch "^2.0.5"
-
-mime-db@1.47.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0:
- version "1.47.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
- integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
-
-mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24:
- version "2.1.30"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
- integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
- dependencies:
- mime-db "1.47.0"
-
-mime@1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
- integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
-
-mime@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
- integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
-mime@^2.3.1:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
- integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
+ picomatch "^2.2.3"
mimic-fn@^2.1.0:
version "2.1.0"
- resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
-mimic-response@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
- integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-
min-indent@^1.0.0:
version "1.0.1"
- resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
-minimalistic-assert@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
- integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
-
-minimatch-all@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/minimatch-all/-/minimatch-all-1.1.0.tgz#40c496a27a2e128d19bf758e76bb01a0c7145787"
- integrity sha1-QMSWonouEo0Zv3WOdrsBoMcUV4c=
- dependencies:
- minimatch "^3.0.2"
-
-"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
- dependencies:
- brace-expansion "^1.1.7"
-
minimatch@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
@@ -7024,68 +1926,35 @@
dependencies:
brace-expansion "^1.0.0"
+minimatch@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+ integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+ dependencies:
+ brace-expansion "^1.1.7"
+
minimist-options@4.1.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
dependencies:
arrify "^1.0.1"
is-plain-obj "^1.1.0"
kind-of "^6.0.3"
-minimist@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.1.tgz#827ba4e7593464e7c221e8c5bed930904ee2c455"
- integrity sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg==
-
-minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
+minimist@^1.2.0, minimist@^1.2.5:
version "1.2.5"
- resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-mixin-deep@^1.2.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
- integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
- dependencies:
- for-in "^1.0.2"
- is-extendable "^1.0.1"
-
-mkdirp@^0.5.0, mkdirp@^0.5.1:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
-
-mkdirp@^1.0.0, mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-moment@^2.15.1, moment@^2.24.0:
- version "2.29.1"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
- integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
-
-mout@^1.0.0:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/mout/-/mout-1.2.2.tgz#c9b718a499806a0632cede178e80f436259e777d"
- integrity sha512-w0OUxFEla6z3d7sVpMZGBCpQvYh8PHS1wZ6Wu9GNKHMpAHWJ0if0LsQZh3DlOqw55HlhJEOMLpFnwtxp99Y5GA==
-
ms@2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-ms@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
- integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
ms@2.1.2:
version "2.1.2"
- resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.1.1:
@@ -7093,148 +1962,24 @@
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-multer@^1.3.0:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.2.tgz#2f1f4d12dbaeeba74cb37e623f234bf4d3d2057a"
- integrity sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==
- dependencies:
- append-field "^1.0.0"
- busboy "^0.2.11"
- concat-stream "^1.5.2"
- mkdirp "^0.5.1"
- object-assign "^4.1.1"
- on-finished "^2.3.0"
- type-is "^1.6.4"
- xtend "^4.0.0"
-
-multimatch@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b"
- integrity sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=
- dependencies:
- array-differ "^1.0.0"
- array-union "^1.0.1"
- arrify "^1.0.0"
- minimatch "^3.0.0"
-
-multimatch@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3"
- integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==
- dependencies:
- "@types/minimatch" "^3.0.3"
- array-differ "^3.0.0"
- array-union "^2.1.0"
- arrify "^2.0.1"
- minimatch "^3.0.4"
-
-multipipe@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-1.0.2.tgz#cc13efd833c9cda99f224f868461b8e1a3fd939d"
- integrity sha1-zBPv2DPJzamfIk+GhGG44aP9k50=
- dependencies:
- duplexer2 "^0.1.2"
- object-assign "^4.1.0"
-
-mute-stream@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.6.tgz#48962b19e169fd1dfc240b3f1e7317627bbc47db"
- integrity sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=
-
mute-stream@0.0.8:
version "0.0.8"
- resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
-mz@^2.4.0, mz@^2.6.0:
- version "2.7.0"
- resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
- integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
- dependencies:
- any-promise "^1.0.0"
- object-assign "^4.0.1"
- thenify-all "^1.0.0"
-
-nan@^2.12.1:
- version "2.14.2"
- resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
- integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
-
-nanomatch@^1.2.9:
- version "1.2.13"
- resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
- integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
- dependencies:
- arr-diff "^4.0.0"
- array-unique "^0.3.2"
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- fragment-cache "^0.2.1"
- is-windows "^1.0.2"
- kind-of "^6.0.2"
- object.pick "^1.3.0"
- regex-not "^1.0.0"
- snapdragon "^0.8.1"
- to-regex "^3.0.1"
-
-native-promise-only@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/native-promise-only/-/native-promise-only-0.8.1.tgz#20a318c30cb45f71fe7adfbf7b21c99c1472ef11"
- integrity sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=
-
natural-compare@^1.4.0:
version "1.4.0"
- resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
ncp@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=
-negotiator@0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
- integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
-
-nice-try@^1.0.4:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
- integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
-
-no-case@^2.2.0:
- version "2.3.2"
- resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
- integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
- dependencies:
- lower-case "^1.1.1"
-
-node-fetch@^2.6.0, node-fetch@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
- integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
-
-node-releases@^1.1.70:
- version "1.1.71"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
- integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
-
-node-status-codes@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
- integrity sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=
-
-nomnom@^1.8.1:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7"
- integrity sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=
- dependencies:
- chalk "~0.4.0"
- underscore "~1.6.0"
-
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0:
+normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
- resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
dependencies:
hosted-git-info "^2.1.4"
@@ -7243,54 +1988,23 @@
validate-npm-package-license "^3.0.1"
normalize-package-data@^3.0.0:
- version "3.0.2"
- resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz"
- integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e"
+ integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==
dependencies:
hosted-git-info "^4.0.1"
- resolve "^1.20.0"
+ is-core-module "^2.5.0"
semver "^7.3.4"
validate-npm-package-license "^3.0.1"
-normalize-path@^2.0.0, normalize-path@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
- integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
- dependencies:
- remove-trailing-separator "^1.0.1"
-
-normalize-path@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
- integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
normalize-url@^4.1.0:
- version "4.5.0"
- resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz"
- integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
+ version "4.5.1"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
+ integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
-npm-api@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/npm-api/-/npm-api-1.0.1.tgz#3def9b51afedca57db14ca0c970d92442d21c9c5"
- integrity sha512-4sITrrzEbPcr0aNV28QyOmgn6C9yKiF8k92jn4buYAK8wmA5xo1qL3II5/gT1r7wxbXBflSduZ2K3FbtOrtGkA==
- dependencies:
- JSONStream "^1.3.5"
- clone-deep "^4.0.1"
- download-stats "^0.3.4"
- moment "^2.24.0"
- node-fetch "^2.6.0"
- paged-request "^2.0.1"
-
-npm-run-path@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
- integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
- dependencies:
- path-key "^2.0.0"
-
-npm-run-path@^4.0.0, npm-run-path@^4.0.1:
+npm-run-path@^4.0.1:
version "4.0.1"
- resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
@@ -7302,50 +2016,19 @@
dependencies:
boolbase "~1.0.0"
-number-is-nan@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
- integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-
-oauth-sign@~0.9.0:
- version "0.9.0"
- resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
- integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-
-object-assign@^4, object-assign@^4.0.0, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-copy@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
- integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
- dependencies:
- copy-descriptor "^0.1.0"
- define-property "^0.2.5"
- kind-of "^3.0.3"
-
-object-inspect@^1.9.0:
- version "1.9.0"
- resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz"
- integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==
+object-inspect@^1.11.0, object-inspect@^1.9.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
+ integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
object-keys@^1.0.12, object-keys@^1.1.1:
version "1.1.1"
- resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
-object-visit@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
- integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
- dependencies:
- isobject "^3.0.0"
-
-object.assign@^4.1.0, object.assign@^4.1.2:
+object.assign@^4.1.2:
version "4.1.2"
- resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940"
integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==
dependencies:
call-bind "^1.0.0"
@@ -7353,89 +2036,32 @@
has-symbols "^1.0.1"
object-keys "^1.1.1"
-object.omit@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
- integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=
- dependencies:
- for-own "^0.1.4"
- is-extendable "^0.1.1"
-
-object.pick@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
- integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
- dependencies:
- isobject "^3.0.1"
-
-object.values@^1.1.1:
- version "1.1.3"
- resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz"
- integrity sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==
+object.values@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30"
+ integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
- es-abstract "^1.18.0-next.2"
- has "^1.0.3"
-
-obuf@^1.0.0, obuf@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
- integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
-
-octokit-pagination-methods@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4"
- integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==
-
-on-finished@^2.3.0, on-finished@~2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
- integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
- dependencies:
- ee-first "1.1.1"
-
-on-headers@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
- integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+ es-abstract "^1.18.2"
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
- resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
dependencies:
wrappy "1"
-one-time@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
- integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
- dependencies:
- fn.name "1.x.x"
-
-onetime@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
- integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
-
onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2"
- resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
-opn@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/opn/-/opn-3.0.3.tgz#b6d99e7399f78d65c3baaffef1fb288e9b85243a"
- integrity sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=
- dependencies:
- object-assign "^4.0.1"
-
optionator@^0.9.1:
version "0.9.1"
- resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
dependencies:
deep-is "^0.1.3"
@@ -7445,145 +2071,57 @@
type-check "^0.4.0"
word-wrap "^1.2.3"
-ordered-read-streams@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b"
- integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s=
- dependencies:
- is-stream "^1.0.1"
- readable-stream "^2.0.1"
-
-os-homedir@^1.0.0, os-homedir@^1.0.1:
+os-tmpdir@~1.0.2:
version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
- integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-
-os-name@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801"
- integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==
- dependencies:
- macos-release "^2.2.0"
- windows-release "^3.1.0"
-
-os-shim@^0.1.2:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
- integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=
-
-os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
- version "1.0.2"
- resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-osenv@^0.1.0, osenv@^0.1.3:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
- integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
- dependencies:
- os-homedir "^1.0.0"
- os-tmpdir "^1.0.0"
-
-p-cancelable@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa"
- integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==
-
p-cancelable@^1.0.0:
version "1.1.0"
- resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-p-cancelable@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.0.tgz#4d51c3b91f483d02a0d300765321fca393d758dd"
- integrity sha512-HAZyB3ZodPo+BDpb4/Iu7Jv4P6cSazBz9ZM0ChhEXp70scx834aWCEjQRwgt41UzzejUAPdbqqONfRWTPYrPAQ==
-
-p-finally@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
- integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
-
p-limit@^1.1.0:
version "1.3.0"
- resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
dependencies:
p-try "^1.0.0"
-p-limit@^2.0.0, p-limit@^2.2.0:
+p-limit@^2.2.0:
version "2.3.0"
- resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
dependencies:
p-try "^2.0.0"
p-locate@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
dependencies:
p-limit "^1.1.0"
-p-locate@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
- integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
- dependencies:
- p-limit "^2.0.0"
-
p-locate@^4.1.0:
version "4.1.0"
- resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
dependencies:
p-limit "^2.2.0"
-p-map@^1.1.1:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b"
- integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==
-
-p-timeout@^1.1.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386"
- integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=
- dependencies:
- p-finally "^1.0.0"
-
p-try@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
-p-try@^2.0.0, p-try@^2.1.0:
+p-try@^2.0.0:
version "2.2.0"
- resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-package-json@^2.0.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-2.4.0.tgz#0d15bd67d1cbbddbb2ca222ff2edb86bcb31a8bb"
- integrity sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=
- dependencies:
- got "^5.0.0"
- registry-auth-token "^3.0.1"
- registry-url "^3.0.3"
- semver "^5.1.0"
-
-package-json@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
- integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
- dependencies:
- got "^6.7.1"
- registry-auth-token "^3.0.1"
- registry-url "^3.0.3"
- semver "^5.1.0"
-
package-json@^6.3.0:
version "6.5.0"
- resolved "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz"
+ resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
dependencies:
got "^9.6.0"
@@ -7591,49 +2129,13 @@
registry-url "^5.0.0"
semver "^6.2.0"
-paged-request@^2.0.1:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/paged-request/-/paged-request-2.0.2.tgz#4d621a08b8d6bee4440a0a92112354eeece5b5b0"
- integrity sha512-NWrGqneZImDdcMU/7vMcAOo1bIi5h/pmpJqe7/jdsy85BA/s5MSaU/KlpxwW/IVPmIwBcq2uKPrBWWhEWhtxag==
- dependencies:
- axios "^0.21.1"
-
-pako@~0.2.0:
- version "0.2.9"
- resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
- integrity sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=
-
-param-case@2.1.x:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
- integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
- dependencies:
- no-case "^2.2.0"
-
parent-module@^1.0.0:
version "1.0.1"
- resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
dependencies:
callsites "^3.0.0"
-parse-glob@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
- integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw=
- dependencies:
- glob-base "^0.3.0"
- is-dotfile "^1.0.0"
- is-extglob "^1.0.0"
- is-glob "^2.0.0"
-
-parse-json@^2.1.0, parse-json@^2.2.0:
- version "2.2.0"
- resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
- integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
- dependencies:
- error-ex "^1.2.0"
-
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
@@ -7644,7 +2146,7 @@
parse-json@^5.0.0:
version "5.2.0"
- resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
dependencies:
"@babel/code-frame" "^7.0.0"
@@ -7652,10 +2154,12 @@
json-parse-even-better-errors "^2.3.0"
lines-and-columns "^1.1.6"
-parse-passwd@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
- integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+parse5-htmlparser2-tree-adapter@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
+ integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
+ dependencies:
+ parse5 "^6.0.1"
parse5@^3.0.1:
version "3.0.3"
@@ -7664,105 +2168,35 @@
dependencies:
"@types/node" "*"
-parse5@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
- integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==
-
-parseqs@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5"
- integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==
-
-parseuri@0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
- integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
-
-parseurl@~1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
- integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
-
-pascalcase@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
- integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
-
-path-dirname@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
- integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
-
-path-exists@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
- integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
- dependencies:
- pinkie-promise "^2.0.0"
+parse5@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
path-exists@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
path-exists@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
path-is-absolute@^1.0.0:
version "1.0.1"
- resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-path-is-inside@^1.0.1, path-is-inside@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
- integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
-
-path-key@^2.0.0, path-key@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
- integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
-
path-key@^3.0.0, path-key@^3.1.0:
version "3.1.1"
- resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
-
-path-to-regexp@0.1.7:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
- integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
-
-path-to-regexp@^1.0.1, path-to-regexp@^1.7.0:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
- integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
- dependencies:
- isarray "0.0.1"
-
-path-type@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
- integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
-path-type@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz"
- integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
- dependencies:
- pify "^2.0.0"
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-type@^3.0.0:
version "3.0.0"
@@ -7773,389 +2207,46 @@
path-type@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-peek-stream@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67"
- integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==
- dependencies:
- buffer-from "^1.0.0"
- duplexify "^3.5.0"
- through2 "^2.0.3"
-
-pem@^1.8.3:
- version "1.14.4"
- resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.4.tgz#a68c70c6e751ccc5b3b5bcd7af78b0aec1177ff9"
- integrity sha512-v8lH3NpirgiEmbOqhx0vwQTxwi0ExsiWBGYh0jYNq7K6mQuO4gI6UEFlr6fLAdv9TPXRt6GqiwE37puQdIDS8g==
- dependencies:
- es6-promisify "^6.0.0"
- md5 "^2.2.1"
- os-tmpdir "^1.0.1"
- which "^2.0.2"
-
-pend@~1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
- integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
-
-performance-now@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
- integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
-
-picomatch@^2.0.5, picomatch@^2.2.1:
- version "2.2.2"
- resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz"
- integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-
-pify@^2.0.0, pify@^2.3.0:
+picomatch@^2.2.3:
version "2.3.0"
- resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
- integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
+ integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
-pify@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
- integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
-
-pinkie-promise@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
- integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
- dependencies:
- pinkie "^2.0.0"
-
-pinkie@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
- integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
-
pkg-dir@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
dependencies:
find-up "^2.1.0"
-plist@^2.0.1:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
- integrity sha1-V8zbeggh3yGDEhejytVOPhRqECU=
+pkg-up@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
+ integrity sha1-yBmscoBZpGHKscOImivjxJoATX8=
dependencies:
- base64-js "1.2.0"
- xmlbuilder "8.2.2"
- xmldom "0.1.x"
-
-plylog@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/plylog/-/plylog-1.1.0.tgz#f6f354e2ae0b01f6db4ed111f4b3855da9c37417"
- integrity sha512-/QnY5aSVaP54va6hruzNtAj02HpsLlAt7V5EndMrtq6ZUTZJKUja43rgiUtGXqm95yrSJjbZoPW0yQQQwLpoJA==
- dependencies:
- logform "^1.9.1"
- winston "^3.0.0"
- winston-transport "^4.2.0"
-
-polymer-analyzer@^3.0.0, polymer-analyzer@^3.1.3, polymer-analyzer@^3.2.2:
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/polymer-analyzer/-/polymer-analyzer-3.2.4.tgz#7d76356620a2328e8bc9e30e47069f9729260ca1"
- integrity sha512-JmxUhMajTuC18tLXbTtu2+aN2x9bTX+4MvCD4IZKJ0rtAL8jWi1iRLfogpHJB4Ig9Dc8EEEuEYipLuzPFl3vqA==
- dependencies:
- "@babel/generator" "^7.0.0-beta.42"
- "@babel/traverse" "^7.0.0-beta.42"
- "@babel/types" "^7.0.0-beta.42"
- "@types/babel-generator" "^6.25.1"
- "@types/babel-traverse" "^6.25.2"
- "@types/babel-types" "^6.25.1"
- "@types/babylon" "^6.16.2"
- "@types/chai-subset" "^1.3.0"
- "@types/chalk" "^0.4.30"
- "@types/clone" "^0.1.30"
- "@types/cssbeautify" "^0.3.1"
- "@types/doctrine" "^0.0.1"
- "@types/is-windows" "^0.2.0"
- "@types/minimatch" "^3.0.1"
- "@types/parse5" "^2.2.34"
- "@types/path-is-inside" "^1.0.0"
- "@types/resolve" "0.0.6"
- "@types/whatwg-url" "^6.4.0"
- babylon "^7.0.0-beta.42"
- cancel-token "^0.1.1"
- chalk "^1.1.3"
- clone "^2.0.0"
- cssbeautify "^0.3.1"
- doctrine "^2.0.2"
- dom5 "^3.0.0"
- indent "0.0.2"
- is-windows "^1.0.2"
- jsonschema "^1.1.0"
- minimatch "^3.0.4"
- parse5 "^4.0.0"
- path-is-inside "^1.0.2"
- resolve "^1.5.0"
- shady-css-parser "^0.1.0"
- stable "^0.1.6"
- strip-indent "^2.0.0"
- vscode-uri "=1.0.6"
- whatwg-url "^6.4.0"
-
-polymer-build@^3.1.0, polymer-build@^3.1.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/polymer-build/-/polymer-build-3.1.4.tgz#ab539f1a13d803518b13b73ffd09198431d98142"
- integrity sha512-OhTOPG5Y/tK2HqGZ5XA/CVDh+TuOaDv7wTZWXDCg6hxeMgNKuljDMn2coyGU5NLM0pLbS+gwFAc2ZJ5cWHCHNg==
- dependencies:
- "@babel/core" "^7.0.0"
- "@babel/plugin-external-helpers" "^7.0.0"
- "@babel/plugin-proposal-async-generator-functions" "^7.0.0"
- "@babel/plugin-proposal-object-rest-spread" "^7.0.0"
- "@babel/plugin-syntax-async-generators" "^7.0.0"
- "@babel/plugin-syntax-dynamic-import" "^7.0.0"
- "@babel/plugin-syntax-import-meta" "^7.0.0"
- "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
- "@babel/plugin-transform-arrow-functions" "^7.0.0"
- "@babel/plugin-transform-async-to-generator" "^7.0.0"
- "@babel/plugin-transform-block-scoped-functions" "^7.0.0"
- "@babel/plugin-transform-block-scoping" "^7.0.0"
- "@babel/plugin-transform-classes" "^7.0.0"
- "@babel/plugin-transform-computed-properties" "^7.0.0"
- "@babel/plugin-transform-destructuring" "^7.0.0"
- "@babel/plugin-transform-duplicate-keys" "^7.0.0"
- "@babel/plugin-transform-exponentiation-operator" "^7.0.0"
- "@babel/plugin-transform-for-of" "^7.0.0"
- "@babel/plugin-transform-function-name" "^7.0.0"
- "@babel/plugin-transform-instanceof" "^7.0.0"
- "@babel/plugin-transform-literals" "^7.0.0"
- "@babel/plugin-transform-modules-amd" "^7.0.0"
- "@babel/plugin-transform-object-super" "^7.0.0"
- "@babel/plugin-transform-parameters" "^7.0.0"
- "@babel/plugin-transform-regenerator" "^7.0.0"
- "@babel/plugin-transform-shorthand-properties" "^7.0.0"
- "@babel/plugin-transform-spread" "^7.0.0"
- "@babel/plugin-transform-sticky-regex" "^7.0.0"
- "@babel/plugin-transform-template-literals" "^7.0.0"
- "@babel/plugin-transform-typeof-symbol" "^7.0.0"
- "@babel/plugin-transform-unicode-regex" "^7.0.0"
- "@babel/traverse" "^7.0.0"
- "@polymer/esm-amd-loader" "^1.0.0"
- "@types/babel-types" "^6.25.1"
- "@types/babylon" "^6.16.2"
- "@types/gulp-if" "0.0.33"
- "@types/html-minifier" "^3.5.1"
- "@types/is-windows" "^0.2.0"
- "@types/mz" "0.0.31"
- "@types/parse5" "^2.2.34"
- "@types/resolve" "0.0.7"
- "@types/uuid" "^3.4.3"
- "@types/vinyl" "^2.0.0"
- "@types/vinyl-fs" "^2.4.8"
- babel-plugin-minify-guarded-expressions "^0.4.3"
- babel-preset-minify "^0.5.0"
- babylon "^7.0.0-beta.42"
- css-slam "^2.1.2"
- dom5 "^3.0.0"
- gulp-if "^2.0.2"
- html-minifier "^3.5.10"
- matcher "^1.1.0"
- multipipe "^1.0.2"
- mz "^2.6.0"
- parse5 "^4.0.0"
- plylog "^1.0.0"
- polymer-analyzer "^3.1.3"
- polymer-bundler "^4.0.9"
- polymer-project-config "^4.0.3"
- regenerator-runtime "^0.11.1"
- stream "0.0.2"
- sw-precache "^5.1.1"
- uuid "^3.2.1"
- vinyl "^1.2.0"
- vinyl-fs "^2.4.4"
-
-polymer-bundler@^4.0.9:
- version "4.0.10"
- resolved "https://registry.yarnpkg.com/polymer-bundler/-/polymer-bundler-4.0.10.tgz#abc8d33977652f031068d034c8104841e80d4cbb"
- integrity sha512-nwlN3LQlQDqbZ2sUH3394C/dHZUDHq8tpdS5HARvPDb0Q9IXWD+znOR1cr7wSjF0EZN4LiUH5hWyUoV4QSjhpQ==
- dependencies:
- "@types/babel-generator" "^6.25.1"
- "@types/babel-traverse" "^6.25.3"
- babel-generator "^6.26.1"
- babel-traverse "^6.26.0"
- babel-types "^6.26.0"
- clone "^2.1.0"
- command-line-args "^5.0.2"
- command-line-usage "^5.0.5"
- dom5 "^3.0.0"
- espree "^3.5.2"
- magic-string "^0.22.4"
- mkdirp "^0.5.1"
- parse5 "^4.0.0"
- polymer-analyzer "^3.2.2"
- rollup "^1.3.0"
- source-map "^0.5.6"
- vscode-uri "=1.0.6"
-
-polymer-cli@^1.9.11:
- version "1.9.11"
- resolved "https://registry.npmjs.org/polymer-cli/-/polymer-cli-1.9.11.tgz"
- integrity sha512-tiURjHDCOUUtDVPuVYvrfFI9PXe4OOUmBbn6Sg5GJNQ2POtP7r7hv+I5yI8P9qsxmalHTa19chVtf5/t9IBXDg==
- dependencies:
- "@octokit/rest" "^16.2.0"
- "@types/chalk" "^2.2.0"
- "@types/del" "^3.0.0"
- "@types/findup-sync" "^0.3.29"
- "@types/globby" "^6.1.0"
- "@types/inquirer" "0.0.32"
- "@types/merge-stream" "^1.0.28"
- "@types/mz" "^0.0.31"
- "@types/request" "2.0.3"
- "@types/resolve" "0.0.4"
- "@types/rimraf" "^0.0.28"
- "@types/semver" "^5.3.30"
- "@types/temp" "^0.8.28"
- "@types/update-notifier" "^1.0.0"
- "@types/vinyl" "^2.0.0"
- "@types/vinyl-fs" "0.0.28"
- "@types/yeoman-generator" "^2.0.3"
- bower "^1.8.8"
- bower-json "^0.8.1"
- bower-logger "^0.2.2"
- chalk "^2.4.2"
- chokidar "^1.7.0"
- command-line-args "^5.0.2"
- command-line-commands "^2.0.1"
- command-line-usage "^5.0.5"
- del "^3.0.0"
- findup-sync "^0.4.2"
- globby "^8.0.1"
- gunzip-maybe "^1.3.1"
- inquirer "^1.0.2"
- merge-stream "^1.0.1"
- mz "^2.6.0"
- plylog "^1.0.0"
- polymer-analyzer "^3.2.2"
- polymer-build "^3.1.4"
- polymer-bundler "^4.0.9"
- polymer-linter "^3.0.0"
- polymer-project-config "^4.0.3"
- polyserve "^0.27.15"
- request "^2.72.0"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar-fs "^1.12.0"
- temp "^0.8.3"
- update-notifier "^1.0.0"
- validate-element-name "^2.1.1"
- vinyl "^1.1.1"
- vinyl-fs "^2.4.3"
- web-component-tester "^6.9.0"
- yeoman-environment "^1.5.2"
- yeoman-generator "^3.1.1"
-
-polymer-linter@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/polymer-linter/-/polymer-linter-3.0.1.tgz#8804e1705fa2a7c263467b8a22da11bb764ee26b"
- integrity sha512-eDh2CeswZz4Rwf8gfYXpMN66pieq4qJvP9bH3m39LLGm81hRePo4N5OHoQzR5unen1PUdmtjDv0Iicz3dTYEZQ==
- dependencies:
- "@types/fast-levenshtein" "0.0.1"
- "@types/parse5" "^2.2.34"
- babel-traverse "^6.26.0"
- babel-types "^6.26.0"
- cancel-token "^0.1.1"
- css-what "^2.1.0"
- dom5 "^3.0.0"
- fast-levenshtein "^2.0.6"
- parse5 "^4.0.0"
- polymer-analyzer "^3.0.0"
- shady-css-parser "^0.1.0"
- stable "^0.1.6"
- strip-indent "^2.0.0"
- validate-element-name "^2.1.1"
-
-polymer-project-config@^4.0.0, polymer-project-config@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/polymer-project-config/-/polymer-project-config-4.0.3.tgz#ef0c1a676ce4809907986c8e910745660de8024f"
- integrity sha512-Drr+Imq+znhBC8XSt9pMlmPixoGnIOmleV5SD6mto1zOGC5oCDbSNsQL2v89DWOk+9aSUO79vnWwOmEPDSvYfw==
- dependencies:
- "@types/parse5" "^2.2.34"
- browser-capabilities "^1.0.0"
- jsonschema "^1.1.1"
- minimatch-all "^1.1.0"
- plylog "^1.0.0"
- winston "^3.0.0"
-
-polyserve@^0.27.13, polyserve@^0.27.15:
- version "0.27.15"
- resolved "https://registry.yarnpkg.com/polyserve/-/polyserve-0.27.15.tgz#261fa5a0873c8d95fd7068598f44c9dac20cf9c4"
- integrity sha512-AaFgANt+tUUVgHLw+BnaVYcn649JiwL1ru0TOZUKj1gGGn/Bq2S16gxql+1muGpRaAsgFu13Zu7k5XkwatwwSg==
- dependencies:
- "@types/compression" "^0.0.33"
- "@types/content-type" "^1.1.0"
- "@types/escape-html" "0.0.20"
- "@types/express" "^4.0.36"
- "@types/mime" "^2.0.0"
- "@types/mz" "0.0.29"
- "@types/opn" "^3.0.28"
- "@types/parse5" "^2.2.34"
- "@types/pem" "^1.8.1"
- "@types/resolve" "0.0.6"
- "@types/serve-static" "^1.7.31"
- "@types/spdy" "^3.4.1"
- bower-config "^1.4.1"
- browser-capabilities "^1.0.0"
- command-line-args "^5.0.2"
- command-line-usage "^5.0.5"
- compression "^1.6.2"
- content-type "^1.0.2"
- cors "^2.8.4"
- escape-html "^1.0.3"
- express "^4.8.5"
- find-port "^1.0.1"
- http-proxy-middleware "^0.17.2"
- lru-cache "^4.0.2"
- mime "^2.3.1"
- mz "^2.4.0"
- opn "^3.0.2"
- pem "^1.8.3"
- polymer-build "^3.1.0"
- polymer-project-config "^4.0.0"
- requirejs "^2.3.4"
- resolve "^1.5.0"
- send "^0.16.2"
- spdy "^3.3.3"
-
-posix-character-classes@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
- integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+ find-up "^2.1.0"
prelude-ls@^1.2.1:
version "1.2.1"
- resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-prepend-http@^1.0.1:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
- integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
-
prepend-http@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-preserve@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
- integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
-
prettier-linter-helpers@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
dependencies:
fast-diff "^1.1.2"
@@ -8166,33 +2257,18 @@
integrity sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==
prettier@^2.1.2:
- version "2.2.1"
- resolved "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz"
- integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
+ integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==
-pretty-bytes@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-4.0.2.tgz#b2bf82e7350d65c6c33aa95aaa5a4f6327f61cd9"
- integrity sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=
-
-pretty-bytes@^5.1.0, pretty-bytes@^5.2.0:
- version "5.6.0"
- resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
- integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
-
-process-nextick-args@^2.0.0, process-nextick-args@~2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
- integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
-progress@2.0.3, progress@^2.0.0:
+progress@^2.0.0:
version "2.0.3"
- resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
protobufjs@6.8.8:
version "6.8.8"
- resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz"
+ resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
@@ -8209,131 +2285,39 @@
"@types/node" "^10.1.0"
long "^4.0.0"
-proxy-addr@~2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
- integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
- dependencies:
- forwarded "~0.1.2"
- ipaddr.js "1.9.1"
-
-pseudomap@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
- integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-
-psl@^1.1.24, psl@^1.1.28:
- version "1.8.0"
- resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
- integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
-
-pump@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954"
- integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-pump@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
- integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
pump@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
dependencies:
end-of-stream "^1.1.0"
once "^1.3.1"
-pumpify@^1.3.3:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
- integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
- dependencies:
- duplexify "^3.6.0"
- inherits "^2.0.3"
- pump "^2.0.0"
-
-punycode@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
- integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
-
-punycode@^2.1.0, punycode@^2.1.1:
+punycode@^2.1.0:
version "2.1.1"
- resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
pupa@^2.1.1:
version "2.1.1"
- resolved "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62"
integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==
dependencies:
escape-goat "^2.0.0"
-q@^1.4.1, q@^1.5.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
- integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
-
-qs@6.7.0:
- version "6.7.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
- integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
-
-qs@~6.5.2:
- version "6.5.2"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
- integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
-
queue-microtask@^1.2.2:
version "1.2.3"
- resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
quick-lru@^4.0.1:
version "4.0.1"
- resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
-quick-lru@^5.1.1:
- version "5.1.1"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
- integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
-
-randomatic@^3.0.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
- integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==
- dependencies:
- is-number "^4.0.0"
- kind-of "^6.0.0"
- math-random "^1.0.1"
-
-range-parser@~1.2.0, range-parser@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
- integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-
-raw-body@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
- integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
- dependencies:
- bytes "3.1.0"
- http-errors "1.7.2"
- iconv-lite "0.4.24"
- unpipe "1.0.0"
-
-rc@^1.0.1, rc@^1.1.6, rc@^1.2.8:
+rc@^1.2.8:
version "1.2.8"
- resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
dependencies:
deep-extend "^0.6.0"
@@ -8341,81 +2325,23 @@
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-read-all-stream@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/read-all-stream/-/read-all-stream-3.1.0.tgz#35c3e177f2078ef789ee4bfafa4373074eaef4fa"
- integrity sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=
- dependencies:
- pinkie-promise "^2.0.0"
- readable-stream "^2.0.0"
-
-read-chunk@^3.0.0, read-chunk@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-3.2.0.tgz#2984afe78ca9bfbbdb74b19387bf9e86289c16ca"
- integrity sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==
- dependencies:
- pify "^4.0.1"
- with-open-file "^0.1.6"
-
-read-pkg-up@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
- integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
- dependencies:
- find-up "^1.0.0"
- read-pkg "^1.0.0"
-
-read-pkg-up@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz"
- integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
+read-pkg-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
+ integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=
dependencies:
find-up "^2.0.0"
- read-pkg "^2.0.0"
-
-read-pkg-up@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
- integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==
- dependencies:
- find-up "^3.0.0"
read-pkg "^3.0.0"
-read-pkg-up@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-5.0.0.tgz#b6a6741cb144ed3610554f40162aa07a6db621b8"
- integrity sha512-XBQjqOBtTzyol2CpsQOw8LHV0XbDZVG7xMMjmXAJomlVY03WOBRmYgDJETlvcg0H63AJvPRwT7GFi5rvOzUOKg==
- dependencies:
- find-up "^3.0.0"
- read-pkg "^5.0.0"
-
read-pkg-up@^7.0.1:
version "7.0.1"
- resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
dependencies:
find-up "^4.1.0"
read-pkg "^5.2.0"
type-fest "^0.8.1"
-read-pkg@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
- integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
- dependencies:
- load-json-file "^1.0.0"
- normalize-package-data "^2.3.2"
- path-type "^1.0.0"
-
-read-pkg@^2.0.0:
- version "2.0.0"
- resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz"
- integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
- dependencies:
- load-json-file "^2.0.0"
- normalize-package-data "^2.3.2"
- path-type "^2.0.0"
-
read-pkg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -8425,9 +2351,9 @@
normalize-package-data "^2.3.2"
path-type "^3.0.0"
-read-pkg@^5.0.0, read-pkg@^5.2.0:
+read-pkg@^5.2.0:
version "5.2.0"
- resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
dependencies:
"@types/normalize-package-data" "^2.4.0"
@@ -8435,17 +2361,7 @@
parse-json "^5.0.0"
type-fest "^0.6.0"
-readable-stream@1.1.x:
- version "1.1.14"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
- integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk=
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-"readable-stream@2 || 3", readable-stream@^3.1.1, readable-stream@^3.4.0:
+readable-stream@^3.1.1:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@@ -8454,311 +2370,56 @@
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
-"readable-stream@>=1.0.33-1 <1.1.0-0":
- version "1.0.34"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
- integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.1"
- isarray "0.0.1"
- string_decoder "~0.10.x"
-
-readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6:
- version "2.3.7"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
- integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readdirp@^2.0.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
- integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
- dependencies:
- graceful-fs "^4.1.11"
- micromatch "^3.1.10"
- readable-stream "^2.0.2"
-
-rechoir@^0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
- integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=
- dependencies:
- resolve "^1.1.6"
-
-redent@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
- integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
- dependencies:
- indent-string "^2.1.0"
- strip-indent "^1.0.1"
-
redent@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
dependencies:
indent-string "^4.0.0"
strip-indent "^3.0.0"
-reduce-flatten@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
- integrity sha1-JYx479FT3fk8tWEjf2EYTzaW4yc=
-
-regenerate-unicode-properties@^8.2.0:
- version "8.2.0"
- resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
- integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
- dependencies:
- regenerate "^1.4.0"
-
-regenerate@^1.4.0:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
- integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
-
-regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
- integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-
-regenerator-runtime@^0.13.4:
- version "0.13.7"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
- integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
-
-regenerator-transform@^0.14.2:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
- integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
- dependencies:
- "@babel/runtime" "^7.8.4"
-
-regex-cache@^0.4.2:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd"
- integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==
- dependencies:
- is-equal-shallow "^0.1.3"
-
-regex-not@^1.0.0, regex-not@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
- integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
- dependencies:
- extend-shallow "^3.0.2"
- safe-regex "^1.1.0"
-
regexpp@^3.0.0, regexpp@^3.1.0:
- version "3.1.0"
- resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz"
- integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
-
-regexpu-core@^4.7.1:
- version "4.7.1"
- resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
- integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
- dependencies:
- regenerate "^1.4.0"
- regenerate-unicode-properties "^8.2.0"
- regjsgen "^0.5.1"
- regjsparser "^0.6.4"
- unicode-match-property-ecmascript "^1.0.4"
- unicode-match-property-value-ecmascript "^1.2.0"
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
+ integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
regextras@^0.7.1:
version "0.7.1"
- resolved "https://registry.npmjs.org/regextras/-/regextras-0.7.1.tgz"
+ resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.7.1.tgz#be95719d5f43f9ef0b9fa07ad89b7c606995a3b2"
integrity sha512-9YXf6xtW+qzQ+hcMQXx95MOvfqXFgsKDZodX3qZB0x2n5Z94ioetIITsBtvJbiOyxa/6s9AtyweBLCdPmPko/w==
-registry-auth-token@^3.0.1:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
- integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
- dependencies:
- rc "^1.1.6"
- safe-buffer "^5.0.1"
-
registry-auth-token@^4.0.0:
version "4.2.1"
- resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250"
integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==
dependencies:
rc "^1.2.8"
-registry-url@^3.0.3:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
- integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
- dependencies:
- rc "^1.0.1"
-
registry-url@^5.0.0:
version "5.1.0"
- resolved "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
dependencies:
rc "^1.2.8"
-regjsgen@^0.5.1:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
- integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
-
-regjsparser@^0.6.4:
- version "0.6.9"
- resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
- integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
- dependencies:
- jsesc "~0.5.0"
-
-relateurl@0.2.x:
- version "0.2.7"
- resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
- integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
-
-remove-trailing-separator@^1.0.1:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
- integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
-
-repeat-element@^1.1.2:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9"
- integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==
-
-repeat-string@^1.5.2, repeat-string@^1.6.1:
- version "1.6.1"
- resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
- integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
-
-repeating@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
- integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
- dependencies:
- is-finite "^1.0.0"
-
-replace-ext@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924"
- integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=
-
-replace-ext@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a"
- integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==
-
-request@2.88.0:
- version "2.88.0"
- resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
- integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
- dependencies:
- aws-sign2 "~0.7.0"
- aws4 "^1.8.0"
- caseless "~0.12.0"
- combined-stream "~1.0.6"
- extend "~3.0.2"
- forever-agent "~0.6.1"
- form-data "~2.3.2"
- har-validator "~5.1.0"
- http-signature "~1.2.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.19"
- oauth-sign "~0.9.0"
- performance-now "^2.1.0"
- qs "~6.5.2"
- safe-buffer "^5.1.2"
- tough-cookie "~2.4.3"
- tunnel-agent "^0.6.0"
- uuid "^3.3.2"
-
-request@^2.72.0, request@^2.85.0:
- version "2.88.2"
- resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
- integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
- dependencies:
- aws-sign2 "~0.7.0"
- aws4 "^1.8.0"
- caseless "~0.12.0"
- combined-stream "~1.0.6"
- extend "~3.0.2"
- forever-agent "~0.6.1"
- form-data "~2.3.2"
- har-validator "~5.1.3"
- http-signature "~1.2.0"
- is-typedarray "~1.0.0"
- isstream "~0.1.2"
- json-stringify-safe "~5.0.1"
- mime-types "~2.1.19"
- oauth-sign "~0.9.0"
- performance-now "^2.1.0"
- qs "~6.5.2"
- safe-buffer "^5.1.2"
- tough-cookie "~2.5.0"
- tunnel-agent "^0.6.0"
- uuid "^3.3.2"
-
require-from-string@^2.0.2:
version "2.0.2"
- resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
-requirejs@^2.3.4:
- version "2.3.6"
- resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9"
- integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg==
-
-requires-port@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
- integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
-
-resolve-alpn@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.1.1.tgz#4a006a7d533c81a5dd04681612090fde227cd6e1"
- integrity sha512-0KbFjFPR2bnJhNx1t8Ad6RqVc8+QPJC4y561FYyC/Q/6OzB3fhUzB5PEgitYhPK6aifwR5gXBSnDMllaDWixGQ==
-
-resolve-dir@^0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e"
- integrity sha1-shklmlYC+sXFxJatiUpujMQwJh4=
- dependencies:
- expand-tilde "^1.2.2"
- global-modules "^0.2.3"
-
-resolve-dir@^1.0.0, resolve-dir@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
- integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
- dependencies:
- expand-tilde "^2.0.0"
- global-modules "^1.0.0"
+requireindex@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef"
+ integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==
resolve-from@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-resolve-url@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
- integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-
-resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.5.0:
+resolve@^1.10.0, resolve@^1.10.1, resolve@^1.20.0:
version "1.20.0"
- resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
dependencies:
is-core-module "^2.2.0"
@@ -8766,507 +2427,139 @@
responselike@^1.0.2:
version "1.0.2"
- resolved "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
dependencies:
lowercase-keys "^1.0.0"
-responselike@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723"
- integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==
- dependencies:
- lowercase-keys "^2.0.0"
-
-restore-cursor@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
- integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=
- dependencies:
- exit-hook "^1.0.0"
- onetime "^1.0.0"
-
restore-cursor@^3.1.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
dependencies:
onetime "^5.1.0"
signal-exit "^3.0.2"
-ret@~0.1.10:
- version "0.1.15"
- resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
- integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
-
reusify@^1.0.4:
version "1.0.4"
- resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
-rimraf@^3.0.0, rimraf@^3.0.2:
+rimraf@^3.0.2:
version "3.0.2"
- resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
-rimraf@~2.6.2:
- version "2.6.3"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
- integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
- dependencies:
- glob "^7.1.3"
-
-rollup@^1.3.0:
- version "1.32.1"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.32.1.tgz#4480e52d9d9e2ae4b46ba0d9ddeaf3163940f9c4"
- integrity sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==
- dependencies:
- "@types/estree" "*"
- "@types/node" "*"
- acorn "^7.1.0"
-
rollup@^2.45.2:
- version "2.45.2"
- resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.45.2.tgz#8fb85917c9f35605720e92328f3ccbfba6f78b48"
- integrity sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ==
+ version "2.56.3"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.3.tgz#b63edadd9851b0d618a6d0e6af8201955a77aeff"
+ integrity sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg==
optionalDependencies:
- fsevents "~2.3.1"
+ fsevents "~2.3.2"
-run-async@^2.0.0, run-async@^2.2.0, run-async@^2.4.0:
+run-async@^2.4.0:
version "2.4.1"
- resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
run-parallel@^1.1.9:
version "1.2.0"
- resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
dependencies:
queue-microtask "^1.2.2"
-rx@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
- integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
-
-rxjs@^6.4.0, rxjs@^6.6.0:
+rxjs@^6.6.0:
version "6.6.7"
- resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
dependencies:
tslib "^1.9.0"
-safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
+safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-safe-regex@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
- integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
- dependencies:
- ret "~0.1.10"
-
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
- resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-samsam@1.x, samsam@^1.1.3:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
- integrity sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==
-
-sauce-connect-launcher@^1.0.0:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-1.3.2.tgz#dfc675a258550809a8eaf457eb9162b943ddbaf0"
- integrity sha512-wf0coUlidJ7rmeClgVVBh6Kw55/yalZCY/Un5RgjSnTXRAeGqagnTsTYpZaqC4dCtrY4myuYpOAZXCdbO7lHfQ==
- dependencies:
- adm-zip "~0.4.3"
- async "^2.1.2"
- https-proxy-agent "^5.0.0"
- lodash "^4.16.6"
- rimraf "^2.5.4"
-
-scoped-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8"
- integrity sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=
-
-select-hose@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
- integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
-
-selenium-standalone@^6.7.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/selenium-standalone/-/selenium-standalone-6.23.0.tgz#91a7d12b1c8ba077a82b44323445c5882eb20ff1"
- integrity sha512-6dVLSEvbixd/MRSEmrcRQD8dmABrzNsxRqroKFQY+RVzm1JVPgGHIlo6qJzG6akfjc2V8SadHslE6lN4BFVM3w==
- dependencies:
- commander "^2.20.3"
- cross-spawn "^7.0.3"
- debug "^4.3.1"
- got "^11.8.0"
- lodash.mapvalues "^4.6.0"
- lodash.merge "^4.6.2"
- minimist "^1.2.5"
- mkdirp "^1.0.4"
- progress "2.0.3"
- tar-stream "2.1.4"
- which "^2.0.2"
- yauzl "^2.10.0"
-
-semver-diff@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
- integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
- dependencies:
- semver "^5.0.3"
-
semver-diff@^3.1.1:
version "3.1.1"
- resolved "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
dependencies:
semver "^6.3.0"
-"semver@2 || 3 || 4 || 5", semver@5.6.0, semver@^5.3.0:
- version "5.6.0"
- resolved "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz"
- integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
-
-semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
+"semver@2 || 3 || 4 || 5":
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
+semver@5.6.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004"
+ integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==
+
semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0:
version "6.3.0"
- resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
+semver@^7.2.1, semver@^7.3.4, semver@^7.3.5:
version "7.3.5"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
dependencies:
lru-cache "^6.0.0"
-send@0.17.1:
- version "0.17.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
- integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
- dependencies:
- debug "2.6.9"
- depd "~1.1.2"
- destroy "~1.0.4"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "~1.7.2"
- mime "1.6.0"
- ms "2.1.1"
- on-finished "~2.3.0"
- range-parser "~1.2.1"
- statuses "~1.5.0"
-
-send@^0.16.1, send@^0.16.2:
- version "0.16.2"
- resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
- integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
- dependencies:
- debug "2.6.9"
- depd "~1.1.2"
- destroy "~1.0.4"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "~1.6.2"
- mime "1.4.1"
- ms "2.0.0"
- on-finished "~2.3.0"
- range-parser "~1.2.0"
- statuses "~1.4.0"
-
-serve-static@1.14.1:
- version "1.14.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
- integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
- dependencies:
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- parseurl "~1.3.3"
- send "0.17.1"
-
-server-destroy@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd"
- integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=
-
-serviceworker-cache-polyfill@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz#de19ee73bef21ab3c0740a37b33db62464babdeb"
- integrity sha1-3hnuc77yGrPAdAo3sz22JGS6ves=
-
-set-getter@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376"
- integrity sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=
- dependencies:
- to-object-path "^0.3.0"
-
-set-value@^2.0.0, set-value@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
- integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
- dependencies:
- extend-shallow "^2.0.1"
- is-extendable "^0.1.1"
- is-plain-object "^2.0.3"
- split-string "^3.0.1"
-
-setprototypeof@1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
- integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
-
-setprototypeof@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
- integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
-
-shady-css-parser@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/shady-css-parser/-/shady-css-parser-0.1.0.tgz#534dc79c8ca5884c5ed92a4e5a13d6d863bca428"
- integrity sha512-irfJUUkEuDlNHKZNAp2r7zOyMlmbfVJ+kWSfjlCYYUx/7dJnANLCyTzQZsuxy5NJkvtNwSxY5Gj8MOlqXUQPyA==
-
-shallow-clone@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
- integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
- dependencies:
- kind-of "^6.0.2"
-
-shebang-command@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
- integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
- dependencies:
- shebang-regex "^1.0.0"
-
shebang-command@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
-shebang-regex@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
- integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
-
shebang-regex@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-shelljs@^0.8.0, shelljs@^0.8.4:
- version "0.8.4"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
- integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
+side-channel@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
+ integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==
dependencies:
- glob "^7.0.0"
- interpret "^1.0.0"
- rechoir "^0.6.2"
+ call-bind "^1.0.0"
+ get-intrinsic "^1.0.2"
+ object-inspect "^1.9.0"
-signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
+signal-exit@^3.0.2, signal-exit@^3.0.3:
version "3.0.3"
- resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-simple-swizzle@^0.2.2:
- version "0.2.2"
- resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
- integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=
- dependencies:
- is-arrayish "^0.3.1"
-
-sinon-chai@^2.10.0:
- version "2.14.0"
- resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-2.14.0.tgz#da7dd4cc83cd6a260b67cca0f7a9fdae26a1205d"
- integrity sha512-9stIF1utB0ywNHNT7RgiXbdmen8QDCRsrTjw+G9TgKt1Yexjiv8TOWZ6WHsTPz57Yky3DIswZvEqX8fpuHNDtQ==
-
-sinon@^2.3.5:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.4.1.tgz#021fd64b54cb77d9d2fb0d43cdedfae7629c3a36"
- integrity sha512-vFTrO9Wt0ECffDYIPSP/E5bBugt0UjcBQOfQUMh66xzkyPEnhl/vM2LRZi2ajuTdkH07sA6DzrM6KvdvGIH8xw==
- dependencies:
- diff "^3.1.0"
- formatio "1.2.0"
- lolex "^1.6.0"
- native-promise-only "^0.8.1"
- path-to-regexp "^1.7.0"
- samsam "^1.1.3"
- text-encoding "0.6.4"
- type-detect "^4.0.0"
-
-slash@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
- integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
-
-slash@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
- integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
-
slash@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
slice-ansi@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
dependencies:
ansi-styles "^4.0.0"
astral-regex "^2.0.0"
is-fullwidth-code-point "^3.0.0"
-slide@^1.1.5:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
- integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=
-
-snapdragon-node@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
- integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
- dependencies:
- define-property "^1.0.0"
- isobject "^3.0.0"
- snapdragon-util "^3.0.1"
-
-snapdragon-util@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
- integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
- dependencies:
- kind-of "^3.2.0"
-
-snapdragon@^0.8.1:
- version "0.8.2"
- resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
- integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
- dependencies:
- base "^0.11.1"
- debug "^2.2.0"
- define-property "^0.2.5"
- extend-shallow "^2.0.1"
- map-cache "^0.2.2"
- source-map "^0.5.6"
- source-map-resolve "^0.5.0"
- use "^3.1.0"
-
-socket.io-adapter@~1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9"
- integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==
-
-socket.io-client@2.4.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.4.0.tgz#aafb5d594a3c55a34355562fc8aea22ed9119a35"
- integrity sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==
- dependencies:
- backo2 "1.0.2"
- component-bind "1.0.0"
- component-emitter "~1.3.0"
- debug "~3.1.0"
- engine.io-client "~3.5.0"
- has-binary2 "~1.0.2"
- indexof "0.0.1"
- parseqs "0.0.6"
- parseuri "0.0.6"
- socket.io-parser "~3.3.0"
- to-array "0.1.4"
-
-socket.io-parser@~3.3.0:
- version "3.3.2"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.2.tgz#ef872009d0adcf704f2fbe830191a14752ad50b6"
- integrity sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==
- dependencies:
- component-emitter "~1.3.0"
- debug "~3.1.0"
- isarray "2.0.1"
-
-socket.io-parser@~3.4.0:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.1.tgz#b06af838302975837eab2dc980037da24054d64a"
- integrity sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==
- dependencies:
- component-emitter "1.2.1"
- debug "~4.1.0"
- isarray "2.0.1"
-
-socket.io@^2.0.3:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.4.1.tgz#95ad861c9a52369d7f1a68acf0d4a1b16da451d2"
- integrity sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==
- dependencies:
- debug "~4.1.0"
- engine.io "~3.5.0"
- has-binary2 "~1.0.2"
- socket.io-adapter "~1.1.0"
- socket.io-client "2.4.0"
- socket.io-parser "~3.4.0"
-
-sort-keys-length@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188"
- integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
- dependencies:
- sort-keys "^1.0.0"
-
-sort-keys@^1.0.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
- integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
- dependencies:
- is-plain-obj "^1.0.0"
-
-source-map-resolve@^0.5.0:
- version "0.5.3"
- resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
- integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
- dependencies:
- atob "^2.1.2"
- decode-uri-component "^0.2.0"
- resolve-url "^0.2.1"
- source-map-url "^0.4.0"
- urix "^0.1.0"
-
source-map-support@0.5.9:
version "0.5.9"
- resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f"
integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==
dependencies:
buffer-from "^1.0.0"
@@ -9280,19 +2573,9 @@
buffer-from "^1.0.0"
source-map "^0.6.0"
-source-map-url@^0.4.0:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
- integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
-
-source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7:
- version "0.5.7"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
- integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+source-map@^0.6.0:
version "0.6.1"
- resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
source-map@~0.7.2:
@@ -9300,17 +2583,9 @@
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
-spawn-sync@^1.0.15:
- version "1.0.15"
- resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
- integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY=
- dependencies:
- concat-stream "^1.4.7"
- os-shim "^0.1.2"
-
spdx-correct@^3.0.0:
version "3.1.1"
- resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
dependencies:
spdx-expression-parse "^3.0.0"
@@ -9318,152 +2593,30 @@
spdx-exceptions@^2.1.0:
version "2.3.0"
- resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1:
version "3.0.1"
- resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-license-ids@^3.0.0:
- version "3.0.7"
- resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz"
- integrity sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==
-
-spdy-transport@^2.0.18:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-2.1.1.tgz#c54815d73858aadd06ce63001e7d25fa6441623b"
- integrity sha512-q7D8c148escoB3Z7ySCASadkegMmUZW8Wb/Q1u0/XBgDKMO880rLQDj8Twiew/tYi7ghemKUi/whSYOwE17f5Q==
- dependencies:
- debug "^2.6.8"
- detect-node "^2.0.3"
- hpack.js "^2.1.6"
- obuf "^1.1.1"
- readable-stream "^2.2.9"
- safe-buffer "^5.0.1"
- wbuf "^1.7.2"
-
-spdy@^3.3.3:
- version "3.4.7"
- resolved "https://registry.yarnpkg.com/spdy/-/spdy-3.4.7.tgz#42ff41ece5cc0f99a3a6c28aabb73f5c3b03acbc"
- integrity sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=
- dependencies:
- debug "^2.6.8"
- handle-thing "^1.2.5"
- http-deceiver "^1.2.7"
- safe-buffer "^5.0.1"
- select-hose "^2.0.0"
- spdy-transport "^2.0.18"
-
-split-string@^3.0.1, split-string@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
- integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
- dependencies:
- extend-shallow "^3.0.0"
+ version "3.0.10"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b"
+ integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==
sprintf-js@~1.0.2:
version "1.0.3"
- resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-sshpk@^1.7.0:
- version "1.16.1"
- resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
- integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
- dependencies:
- asn1 "~0.2.3"
- assert-plus "^1.0.0"
- bcrypt-pbkdf "^1.0.0"
- dashdash "^1.12.0"
- ecc-jsbn "~0.1.1"
- getpass "^0.1.1"
- jsbn "~0.1.0"
- safer-buffer "^2.0.2"
- tweetnacl "~0.14.0"
-
-stable@^0.1.6:
- version "0.1.8"
- resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
- integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
-
-stack-trace@0.0.x:
- version "0.0.10"
- resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
- integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
-
-stacky@^1.3.1:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/stacky/-/stacky-1.3.1.tgz#3f117e5187b9a73d23f876d69f05c85b11804a12"
- integrity sha1-PxF+UYe5pz0j+HbWnwXIWxGAShI=
- dependencies:
- chalk "^1.1.1"
- lodash "^3.0.0"
-
-static-extend@^0.1.1:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
- integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
- dependencies:
- define-property "^0.2.5"
- object-copy "^0.1.0"
-
-"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
- integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
-
-statuses@~1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
- integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
-
-stream-shift@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
- integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
-
-stream@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/stream/-/stream-0.0.2.tgz#7f5363f057f6592c5595f00bc80a27f5cec1f0ef"
- integrity sha1-f1Nj8Ff2WSxVlfALyAon9c7B8O8=
- dependencies:
- emitter-component "^1.1.1"
-
-streamsearch@0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
- integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
-
-string-template@~0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add"
- integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=
-
-string-width@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
- integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
- dependencies:
- code-point-at "^1.0.0"
- is-fullwidth-code-point "^1.0.0"
- strip-ansi "^3.0.0"
-
-string-width@^2.0.0, string-width@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
- integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
- dependencies:
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^4.0.0"
-
string-width@^3.0.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
@@ -9472,7 +2625,7 @@
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
version "4.2.2"
- resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
dependencies:
emoji-regex "^8.0.0"
@@ -9481,7 +2634,7 @@
string.prototype.trimend@^1.0.4:
version "1.0.4"
- resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80"
integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==
dependencies:
call-bind "^1.0.2"
@@ -9489,7 +2642,7 @@
string.prototype.trimstart@^1.0.4:
version "1.0.4"
- resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed"
integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==
dependencies:
call-bind "^1.0.2"
@@ -9502,491 +2655,120 @@
dependencies:
safe-buffer "~5.2.0"
-string_decoder@~0.10.x:
- version "0.10.31"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
- integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
-strip-ansi@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
- dependencies:
- ansi-regex "^2.0.0"
-
-strip-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
- integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
- dependencies:
- ansi-regex "^3.0.0"
-
strip-ansi@^5.1.0:
version "5.2.0"
- resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0:
version "6.0.0"
- resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
dependencies:
ansi-regex "^5.0.0"
-strip-ansi@~0.1.0:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991"
- integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=
-
-strip-bom-buf@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
- integrity sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=
- dependencies:
- is-utf8 "^0.2.1"
-
-strip-bom-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
- integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=
- dependencies:
- first-chunk-stream "^1.0.0"
- strip-bom "^2.0.0"
-
-strip-bom-stream@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz#f87db5ef2613f6968aa545abfe1ec728b6a829ca"
- integrity sha1-+H217yYT9paKpUWr/h7HKLaoKco=
- dependencies:
- first-chunk-stream "^2.0.0"
- strip-bom "^2.0.0"
-
-strip-bom@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
- integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
- dependencies:
- is-utf8 "^0.2.0"
-
strip-bom@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
-strip-eof@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
- integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-
strip-final-newline@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-strip-indent@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
- integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
- dependencies:
- get-stdin "^4.0.1"
-
-strip-indent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
- integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
-
strip-indent@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
dependencies:
min-indent "^1.0.0"
strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
version "3.1.1"
- resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
strip-json-comments@~2.0.1:
version "2.0.1"
- resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
-supports-color@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
- integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
-
supports-color@^5.3.0:
version "5.5.0"
- resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
dependencies:
has-flag "^3.0.0"
supports-color@^7.1.0:
version "7.2.0"
- resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
dependencies:
has-flag "^4.0.0"
-sw-precache@^5.1.1:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/sw-precache/-/sw-precache-5.2.1.tgz#06134f319eec68f3b9583ce9a7036b1c119f7179"
- integrity sha512-8FAy+BP/FXE+ILfiVTt+GQJ6UEf4CVHD9OfhzH0JX+3zoy2uFk7Vn9EfXASOtVmmIVbL3jE/W8Z66VgPSZcMhw==
- dependencies:
- dom-urls "^1.1.0"
- es6-promise "^4.0.5"
- glob "^7.1.1"
- lodash.defaults "^4.2.0"
- lodash.template "^4.4.0"
- meow "^3.7.0"
- mkdirp "^0.5.1"
- pretty-bytes "^4.0.2"
- sw-toolbox "^3.4.0"
- update-notifier "^2.3.0"
-
-sw-toolbox@^3.4.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/sw-toolbox/-/sw-toolbox-3.6.0.tgz#26df1d1c70348658e4dea2884319149b7b3183b5"
- integrity sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=
- dependencies:
- path-to-regexp "^1.0.1"
- serviceworker-cache-polyfill "^4.0.0"
-
-table-layout@^0.4.3:
- version "0.4.5"
- resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.4.5.tgz#d906de6a25fa09c0c90d1d08ecd833ecedcb7378"
- integrity sha512-zTvf0mcggrGeTe/2jJ6ECkJHAQPIYEwDoqsiqBjI24mvRmQbInK5jq33fyypaCBxX08hMkfmdOqj6haT33EqWw==
- dependencies:
- array-back "^2.0.0"
- deep-extend "~0.6.0"
- lodash.padend "^4.6.1"
- typical "^2.6.1"
- wordwrapjs "^3.0.0"
-
-table@^6.0.4:
- version "6.0.9"
- resolved "https://registry.npmjs.org/table/-/table-6.0.9.tgz"
- integrity sha512-F3cLs9a3hL1Z7N4+EkSscsel3z55XT950AvB05bwayrNg5T1/gykXtigioTAjbltvbMSJvvhFCbnf6mX+ntnJQ==
+table@^6.0.9:
+ version "6.7.1"
+ resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"
+ integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==
dependencies:
ajv "^8.0.1"
- is-boolean-object "^1.1.0"
- is-number-object "^1.0.4"
- is-string "^1.0.5"
lodash.clonedeep "^4.5.0"
- lodash.flatten "^4.4.0"
lodash.truncate "^4.4.2"
slice-ansi "^4.0.0"
string-width "^4.2.0"
-
-tar-fs@^1.12.0:
- version "1.16.3"
- resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
- integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==
- dependencies:
- chownr "^1.0.1"
- mkdirp "^0.5.1"
- pump "^1.0.0"
- tar-stream "^1.1.2"
-
-tar-stream@2.1.4:
- version "2.1.4"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa"
- integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==
- dependencies:
- bl "^4.0.3"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
-tar-stream@^1.1.2:
- version "1.6.2"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555"
- integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
- dependencies:
- bl "^1.0.0"
- buffer-alloc "^1.2.0"
- end-of-stream "^1.0.0"
- fs-constants "^1.0.0"
- readable-stream "^2.3.0"
- to-buffer "^1.1.1"
- xtend "^4.0.0"
-
-tar-stream@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
- integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
- dependencies:
- bl "^4.0.3"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
-temp@^0.8.1, temp@^0.8.3:
- version "0.8.4"
- resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2"
- integrity sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==
- dependencies:
- rimraf "~2.6.2"
-
-term-size@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
- integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
- dependencies:
- execa "^0.7.0"
-
-ternary-stream@^2.0.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.1.1.tgz#4ad64b98668d796a085af2c493885a435a8a8bfc"
- integrity sha512-j6ei9hxSoyGlqTmoMjOm+QNvUKDOIY6bNl4Uh1lhBvl6yjPW2iLqxDUYyfDPZknQ4KdRziFl+ec99iT4l7g0cw==
- dependencies:
- duplexify "^3.5.0"
- fork-stream "^0.0.4"
- merge-stream "^1.0.0"
- through2 "^2.0.1"
+ strip-ansi "^6.0.0"
terser@^5.6.1:
- version "5.6.1"
- resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.1.tgz#a48eeac5300c0a09b36854bf90d9c26fb201973c"
- integrity sha512-yv9YLFQQ+3ZqgWCUk+pvNJwgUTdlIxUk1WTN+RnaFJe2L7ipG2csPT0ra2XRm7Cs8cxN7QXmK1rFzEwYEQkzXw==
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.2.tgz#d4d95ed4f8bf735cb933e802f2a1829abf545e3f"
+ integrity sha512-0Omye+RD4X7X69O0eql3lC4Heh/5iLj3ggxR/B5ketZLOtLiOqukUgjw3q4PDnNQbsrkKr3UMypqStQG3XKRvw==
dependencies:
commander "^2.20.0"
source-map "~0.7.2"
source-map-support "~0.5.19"
-text-encoding@0.6.4:
- version "0.6.4"
- resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
- integrity sha1-45mpgiV6J22uQou5KEXLcb3CbRk=
-
-text-hex@1.0.x:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
- integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
-
text-table@^0.2.0:
version "0.2.0"
- resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-textextensions@^2.5.0:
- version "2.6.0"
- resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4"
- integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ==
-
-thenify-all@^1.0.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
- integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=
- dependencies:
- thenify ">= 3.1.0 < 4"
-
-"thenify@>= 3.1.0 < 4":
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
- integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
- dependencies:
- any-promise "^1.0.0"
-
-through2-filter@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec"
- integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=
- dependencies:
- through2 "~2.0.0"
- xtend "~4.0.0"
-
-through2-filter@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254"
- integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==
- dependencies:
- through2 "~2.0.0"
- xtend "~4.0.0"
-
-through2@^0.6.0:
- version "0.6.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48"
- integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=
- dependencies:
- readable-stream ">=1.0.33-1 <1.1.0-0"
- xtend ">=4.0.0 <4.1.0-0"
-
-through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0.0:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
- integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
- dependencies:
- readable-stream "~2.3.6"
- xtend "~4.0.1"
-
-through2@^3.0.0, through2@^3.0.1, through2@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4"
- integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==
- dependencies:
- inherits "^2.0.4"
- readable-stream "2 || 3"
-
-"through@>=2.2.7 <3", through@^2.3.6:
+through@^2.3.6:
version "2.3.8"
- resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
-timed-out@^3.0.0:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-3.1.3.tgz#95860bfcc5c76c277f8f8326fd0f5b2e20eba217"
- integrity sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=
-
-timed-out@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
- integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
-
-tmp@^0.0.29:
- version "0.0.29"
- resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.29.tgz#f25125ff0dd9da3ccb0c2dd371ee1288bb9128c0"
- integrity sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA=
- dependencies:
- os-tmpdir "~1.0.1"
-
tmp@^0.0.33:
version "0.0.33"
- resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
dependencies:
os-tmpdir "~1.0.2"
-to-absolute-glob@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
- integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38=
- dependencies:
- extend-shallow "^2.0.1"
-
-to-array@0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
- integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA=
-
-to-buffer@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80"
- integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
-
-to-fast-properties@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
- integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
-
-to-fast-properties@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
- integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
-
-to-object-path@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
- integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
- dependencies:
- kind-of "^3.0.2"
-
to-readable-stream@^1.0.0:
version "1.0.0"
- resolved "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
-to-regex-range@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
- integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
- dependencies:
- is-number "^3.0.0"
- repeat-string "^1.6.1"
-
to-regex-range@^5.0.1:
version "5.0.1"
- resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
dependencies:
is-number "^7.0.0"
-to-regex@^3.0.1, to-regex@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
- integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
- dependencies:
- define-property "^2.0.2"
- extend-shallow "^3.0.2"
- regex-not "^1.0.2"
- safe-regex "^1.1.0"
-
-toidentifier@1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
- integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
-
-tough-cookie@~2.4.3:
- version "2.4.3"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
- integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
- dependencies:
- psl "^1.1.24"
- punycode "^1.4.1"
-
-tough-cookie@~2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
- integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
- dependencies:
- psl "^1.1.28"
- punycode "^2.1.1"
-
-tr46@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
- integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
- dependencies:
- punycode "^2.1.0"
-
-trim-newlines@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
- integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
-
trim-newlines@^3.0.0:
- version "3.0.0"
- resolved "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz"
- integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
+ integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
-trim-right@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
- integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
-
-triple-beam@^1.2.0, triple-beam@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
- integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
-
-tsconfig-paths@^3.9.0:
- version "3.9.0"
- resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz"
- integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
+tsconfig-paths@^3.11.0:
+ version "3.11.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz#954c1fe973da6339c78e06b03ce2e48810b65f36"
+ integrity sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==
dependencies:
"@types/json5" "^0.0.29"
json5 "^1.0.1"
@@ -9995,39 +2777,27 @@
tslib@^1.8.1, tslib@^1.9.0:
version "1.14.1"
- resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tsutils@2.27.2:
version "2.27.2"
- resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.27.2.tgz"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7"
integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg==
dependencies:
tslib "^1.8.1"
-tsutils@^3.17.1, tsutils@^3.21.0:
+tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"
-tunnel-agent@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
- integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
- dependencies:
- safe-buffer "^5.0.1"
-
-tweetnacl@^0.14.3, tweetnacl@~0.14.0:
- version "0.14.5"
- resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
- integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
-
-twinkie@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/twinkie/-/twinkie-1.1.2.tgz#c301e4fc26d00d61d3d7e5be030dc6a2264271da"
- integrity sha512-4KwhyrcrRb0WWJKMX/aT+npmMZC0h+sA//+bLhNupmuKvesrH2vEZDe6yIr48FMWKEsdA2xNdQqw/3MapZ5qXQ==
+twinkie@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/twinkie/-/twinkie-1.1.3.tgz#1a6f0cd11c59e245bc2d16c7c9fc1ec13e477229"
+ integrity sha512-8Y1U/UCtf8JC4snuV4KAo4e9nwJcKZUoMVOApihJzua4JJWeGB/2RYqAusKk3cUczJeZRGzirHpP1hkArcbA8A==
dependencies:
"@types/minimatch" "3.0.3"
cheerio "1.0.0-rc.2"
@@ -10036,97 +2806,51 @@
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
- resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
dependencies:
prelude-ls "^1.2.1"
-type-detect@^4.0.0:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
- integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
-
type-fest@^0.18.0:
version "0.18.1"
- resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
type-fest@^0.20.2:
version "0.20.2"
- resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
type-fest@^0.21.3:
version "0.21.3"
- resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
type-fest@^0.6.0:
version "0.6.0"
- resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
type-fest@^0.8.1:
version "0.8.1"
- resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-type-is@^1.6.4, type-is@~1.6.17, type-is@~1.6.18:
- version "1.6.18"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
- integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
- dependencies:
- media-typer "0.3.0"
- mime-types "~2.1.24"
-
typedarray-to-buffer@^3.1.5:
version "3.1.5"
- resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
dependencies:
is-typedarray "^1.0.0"
-typedarray@^0.0.6:
- version "0.0.6"
- resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
- integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-
-typescript@4.0.5:
- version "4.0.5"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.5.tgz#ae9dddfd1069f1cb5beb3ef3b2170dd7c1332389"
- integrity sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==
-
-typescript@4.3.2:
+typescript@4.0.5, typescript@4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"
integrity sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==
-typical@^2.6.1:
- version "2.6.1"
- resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d"
- integrity sha1-XAgOXWYcu+OCWdLnCjxyU+hziB0=
-
-typical@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
- integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
-
-ua-parser-js@^0.7.15:
- version "0.7.28"
- resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"
- integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==
-
-uglify-js@3.4.x:
- version "3.4.10"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
- integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
- dependencies:
- commander "~2.19.0"
- source-map "~0.6.1"
-
-unbox-primitive@^1.0.0:
+unbox-primitive@^1.0.1:
version "1.0.1"
- resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz"
+ resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471"
integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
dependencies:
function-bind "^1.1.1"
@@ -10134,151 +2858,16 @@
has-symbols "^1.0.2"
which-boxed-primitive "^1.0.2"
-underscore@^1.8.3:
- version "1.13.0"
- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.0.tgz#3ccdcbb824230fc6bf234ad0ddcd83dff4eafe5f"
- integrity sha512-sCs4H3pCytsb5K7i072FAEC9YlSYFIbosvM0tAKAlpSSUgD7yC1iXSEGdl5XrDKQ1YUB+p/HDzYrSG2H2Vl36g==
-
-underscore@~1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.6.0.tgz#8b38b10cacdef63337b8b24e4ff86d45aea529a8"
- integrity sha1-izixDKze9jM3uLJOT/htRa6lKag=
-
-unicode-canonical-property-names-ecmascript@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
- integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
-
-unicode-match-property-ecmascript@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
- integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
- dependencies:
- unicode-canonical-property-names-ecmascript "^1.0.4"
- unicode-property-aliases-ecmascript "^1.0.4"
-
-unicode-match-property-value-ecmascript@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
- integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
-
-unicode-property-aliases-ecmascript@^1.0.4:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
- integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
-
-union-value@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
- integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
- dependencies:
- arr-union "^3.1.0"
- get-value "^2.0.6"
- is-extendable "^0.1.1"
- set-value "^2.0.1"
-
-unique-stream@^2.0.2:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac"
- integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==
- dependencies:
- json-stable-stringify-without-jsonify "^1.0.1"
- through2-filter "^3.0.0"
-
-unique-string@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
- integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
- dependencies:
- crypto-random-string "^1.0.0"
-
unique-string@^2.0.0:
version "2.0.0"
- resolved "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
dependencies:
crypto-random-string "^2.0.0"
-universal-user-agent@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557"
- integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==
- dependencies:
- os-name "^3.1.0"
-
-universal-user-agent@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee"
- integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==
-
-unpipe@1.0.0, unpipe@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
- integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
-
-unset-value@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
- integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
- dependencies:
- has-value "^0.3.1"
- isobject "^3.0.0"
-
-untildify@^2.0.0, untildify@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0"
- integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA=
- dependencies:
- os-homedir "^1.0.0"
-
-untildify@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
- integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==
-
-unzip-response@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
- integrity sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=
-
-unzip-response@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
- integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
-
-update-notifier@^1.0.0:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-1.0.3.tgz#8f92c515482bd6831b7c93013e70f87552c7cf5a"
- integrity sha1-j5LFFUgr1oMbfJMBPnD4dVLHz1o=
- dependencies:
- boxen "^0.6.0"
- chalk "^1.0.0"
- configstore "^2.0.0"
- is-npm "^1.0.0"
- latest-version "^2.0.0"
- lazy-req "^1.1.0"
- semver-diff "^2.0.0"
- xdg-basedir "^2.0.0"
-
-update-notifier@^2.2.0, update-notifier@^2.3.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
- integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
- dependencies:
- boxen "^1.2.1"
- chalk "^2.0.1"
- configstore "^3.0.0"
- import-lazy "^2.1.0"
- is-ci "^1.0.10"
- is-installed-globally "^0.1.0"
- is-npm "^1.0.0"
- latest-version "^3.0.0"
- semver-diff "^2.0.0"
- xdg-basedir "^3.0.0"
-
update-notifier@^5.0.0:
version "5.1.0"
- resolved "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9"
integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==
dependencies:
boxen "^5.0.0"
@@ -10296,284 +2885,41 @@
semver-diff "^3.1.1"
xdg-basedir "^4.0.0"
-upper-case@^1.1.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
- integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
-
uri-js@^4.2.2:
version "4.4.1"
- resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
dependencies:
punycode "^2.1.0"
-urijs@^1.16.1:
- version "1.19.6"
- resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.6.tgz#51f8cb17ca16faefb20b9a31ac60f84aa2b7c870"
- integrity sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw==
-
-urix@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
- integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
-
-url-parse-lax@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
- integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
- dependencies:
- prepend-http "^1.0.1"
-
url-parse-lax@^3.0.0:
version "3.0.0"
- resolved "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
dependencies:
prepend-http "^2.0.0"
-url-to-options@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
- integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
-
-use@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
- integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
-
-util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+util-deprecate@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-utils-merge@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
- integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-
-uuid@^2.0.1:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
- integrity sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=
-
-uuid@^3.2.1, uuid@^3.3.2:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-
v8-compile-cache@^2.0.3:
version "2.3.0"
- resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
-vali-date@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6"
- integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=
-
-validate-element-name@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/validate-element-name/-/validate-element-name-2.1.1.tgz#8ff75f7da69f73e7c510588362130508b7ac644e"
- integrity sha1-j/dffaafc+fFEFiDYhMFCLesZE4=
- dependencies:
- is-potential-custom-element-name "^1.0.0"
- log-symbols "^1.0.0"
- meow "^3.7.0"
-
validate-npm-package-license@^3.0.1:
version "3.0.4"
- resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
dependencies:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
-vargs@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff"
- integrity sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=
-
-vary@^1, vary@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
- integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
-
-verror@1.10.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
- integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
- dependencies:
- assert-plus "^1.0.0"
- core-util-is "1.0.2"
- extsprintf "^1.2.0"
-
-vinyl-file@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-3.0.0.tgz#b104d9e4409ffa325faadd520642d0a3b488b365"
- integrity sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U=
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.3.0"
- strip-bom-buf "^1.0.0"
- strip-bom-stream "^2.0.0"
- vinyl "^2.0.1"
-
-vinyl-fs@^2.4.3, vinyl-fs@^2.4.4:
- version "2.4.4"
- resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239"
- integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=
- dependencies:
- duplexify "^3.2.0"
- glob-stream "^5.3.2"
- graceful-fs "^4.0.0"
- gulp-sourcemaps "1.6.0"
- is-valid-glob "^0.3.0"
- lazystream "^1.0.0"
- lodash.isequal "^4.0.0"
- merge-stream "^1.0.0"
- mkdirp "^0.5.0"
- object-assign "^4.0.0"
- readable-stream "^2.0.4"
- strip-bom "^2.0.0"
- strip-bom-stream "^1.0.0"
- through2 "^2.0.0"
- through2-filter "^2.0.0"
- vali-date "^1.0.0"
- vinyl "^1.0.0"
-
-vinyl@^1.0.0, vinyl@^1.1.1, vinyl@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884"
- integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=
- dependencies:
- clone "^1.0.0"
- clone-stats "^0.0.1"
- replace-ext "0.0.1"
-
-vinyl@^2.0.1, vinyl@^2.2.0, vinyl@^2.2.1:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974"
- integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==
- dependencies:
- clone "^2.1.1"
- clone-buffer "^1.0.0"
- clone-stats "^1.0.0"
- cloneable-readable "^1.0.0"
- remove-trailing-separator "^1.0.1"
- replace-ext "^1.0.0"
-
-vlq@^0.2.2:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.3.tgz#8f3e4328cf63b1540c0d67e1b2778386f8975b26"
- integrity sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==
-
-vscode-uri@=1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d"
- integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww==
-
-wbuf@^1.1.0, wbuf@^1.7.2:
- version "1.7.3"
- resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
- integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
- dependencies:
- minimalistic-assert "^1.0.0"
-
-wct-local@^2.1.1:
- version "2.1.5"
- resolved "https://registry.yarnpkg.com/wct-local/-/wct-local-2.1.5.tgz#f7986753e3ad9a35d39178a9989350523561fff1"
- integrity sha512-eqoZhjGy4Xq2tY0uB46Grkw/ztq+/rC0ImbYKl62unFHXtOgal+kkvnxR3SLRFNM8ty9+ItgycPeH0IpTqVL+w==
- dependencies:
- "@types/express" "^4.0.30"
- "@types/freeport" "^1.0.19"
- "@types/launchpad" "^0.6.0"
- "@types/which" "^1.3.1"
- chalk "^2.3.0"
- cleankill "^2.0.0"
- freeport "^1.0.4"
- launchpad "^0.7.0"
- selenium-standalone "^6.7.0"
- which "^1.0.8"
-
-wct-sauce@^2.0.2:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/wct-sauce/-/wct-sauce-2.1.0.tgz#67d0be346aabbbc28384e8d143b8d3ca7ba774c0"
- integrity sha512-c3R4PJcbpS7Gxv2vZ4HDAqpXV6cT9peslAWMU7hHH9PMhKDPbn8RNa6E4DVL0tOmZznB+3cRmtZ6+vJ/aDwu1A==
- dependencies:
- chalk "^2.4.1"
- cleankill "^2.0.0"
- lodash "^4.17.10"
- request "^2.85.0"
- sauce-connect-launcher "^1.0.0"
- temp "^0.8.1"
- uuid "^3.2.1"
-
-wd@^1.2.0:
- version "1.14.0"
- resolved "https://registry.yarnpkg.com/wd/-/wd-1.14.0.tgz#1fe6450b5baef37caa135e7755292c6998ca8a90"
- integrity sha512-X7ZfGHHYlQ5zYpRlgP16LUsvYti+Al/6fz3T/ClVyivVCpCZQpESTDdz6zbK910O5OIvujO23Ym2DBBo3XsQlA==
- dependencies:
- archiver "^3.0.0"
- async "^2.0.0"
- lodash "^4.0.0"
- mkdirp "^0.5.1"
- q "^1.5.1"
- request "2.88.0"
- vargs "^0.1.0"
-
-web-component-tester@^6.9.0:
- version "6.9.2"
- resolved "https://registry.yarnpkg.com/web-component-tester/-/web-component-tester-6.9.2.tgz#40a7b824f2cf3cbc4305552bdfc3357977ded48a"
- integrity sha512-s2kB/+IE8XWcnxY1fqSpqTiiHEGHWgUWariAbiRlxmAvWSuvaCVNALHYebsZrLCNCLHKcJR8/sGv/bw0MWMvjw==
- dependencies:
- "@polymer/sinonjs" "^1.14.1"
- "@polymer/test-fixture" "^0.0.3"
- "@webcomponents/webcomponentsjs" "^1.0.7"
- accessibility-developer-tools "^2.12.0"
- async "^2.4.1"
- body-parser "^1.17.2"
- bower-config "^1.4.0"
- chalk "^1.1.3"
- cleankill "^2.0.0"
- express "^4.15.3"
- findup-sync "^2.0.0"
- glob "^7.1.2"
- lodash "^3.10.1"
- multer "^1.3.0"
- nomnom "^1.8.1"
- polyserve "^0.27.13"
- resolve "^1.5.0"
- semver "^5.3.0"
- send "^0.16.1"
- server-destroy "^1.0.1"
- sinon "^2.3.5"
- sinon-chai "^2.10.0"
- socket.io "^2.0.3"
- stacky "^1.3.1"
- wd "^1.2.0"
- optionalDependencies:
- update-notifier "^2.2.0"
- wct-local "^2.1.1"
- wct-sauce "^2.0.2"
-
-webidl-conversions@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
- integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
-
-whatwg-url@^6.4.0:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8"
- integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==
- dependencies:
- lodash.sortby "^4.7.0"
- tr46 "^1.0.1"
- webidl-conversions "^4.0.2"
-
which-boxed-primitive@^1.0.2:
version "1.0.2"
- resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==
dependencies:
is-bigint "^1.0.1"
@@ -10582,101 +2928,28 @@
is-string "^1.0.5"
is-symbol "^1.0.3"
-which@^1.0.8, which@^1.2.12, which@^1.2.14, which@^1.2.9:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
- integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
- dependencies:
- isexe "^2.0.0"
-
-which@^2.0.1, which@^2.0.2:
+which@^2.0.1:
version "2.0.2"
- resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
-widest-line@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-1.0.0.tgz#0c09c85c2a94683d0d7eaf8ee097d564bf0e105c"
- integrity sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=
- dependencies:
- string-width "^1.0.1"
-
-widest-line@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
- integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
- dependencies:
- string-width "^2.1.1"
-
widest-line@^3.1.0:
version "3.1.0"
- resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
dependencies:
string-width "^4.0.0"
-windows-release@^3.1.0:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999"
- integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg==
- dependencies:
- execa "^1.0.0"
-
-winston-transport@^4.2.0, winston-transport@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59"
- integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==
- dependencies:
- readable-stream "^2.3.7"
- triple-beam "^1.2.0"
-
-winston@^3.0.0:
- version "3.3.3"
- resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"
- integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==
- dependencies:
- "@dabh/diagnostics" "^2.0.2"
- async "^3.1.0"
- is-stream "^2.0.0"
- logform "^2.2.0"
- one-time "^1.0.0"
- readable-stream "^3.4.0"
- stack-trace "0.0.x"
- triple-beam "^1.3.0"
- winston-transport "^4.4.0"
-
-with-open-file@^0.1.6:
- version "0.1.7"
- resolved "https://registry.yarnpkg.com/with-open-file/-/with-open-file-0.1.7.tgz#e2de8d974e8a8ae6e58886be4fe8e7465b58a729"
- integrity sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==
- dependencies:
- p-finally "^1.0.0"
- p-try "^2.1.0"
- pify "^4.0.1"
-
word-wrap@^1.2.3:
version "1.2.3"
- resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
-wordwrap@^0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
- integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
-
-wordwrapjs@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/wordwrapjs/-/wordwrapjs-3.0.0.tgz#c94c372894cadc6feb1a66bff64e1d9af92c5d1e"
- integrity sha512-mO8XtqyPvykVCsrwj5MlOVWvSnCdT+C+QVbm6blradR7JExAhbkZ7hZ9A+9NUtwzSqrlUo9a67ws0EiILrvRpw==
- dependencies:
- reduce-flatten "^1.0.1"
- typical "^2.6.1"
-
wrap-ansi@^7.0.0:
version "7.0.0"
- resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
@@ -10685,30 +2958,12 @@
wrappy@1:
version "1.0.2"
- resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-write-file-atomic@^1.1.2:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f"
- integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=
- dependencies:
- graceful-fs "^4.1.11"
- imurmurhash "^0.1.4"
- slide "^1.1.5"
-
-write-file-atomic@^2.0.0:
- version "2.4.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
- integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
- dependencies:
- graceful-fs "^4.1.11"
- imurmurhash "^0.1.4"
- signal-exit "^3.0.2"
-
write-file-atomic@^3.0.0, write-file-atomic@^3.0.3:
version "3.0.3"
- resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
dependencies:
imurmurhash "^0.1.4"
@@ -10716,189 +2971,17 @@
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
-ws@~7.4.2:
- version "7.4.4"
- resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
- integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
-
-xdg-basedir@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-2.0.0.tgz#edbc903cc385fc04523d966a335504b5504d1bd2"
- integrity sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=
- dependencies:
- os-homedir "^1.0.0"
-
-xdg-basedir@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
- integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
-
xdg-basedir@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
-xmlbuilder@8.2.2:
- version "8.2.2"
- resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
- integrity sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=
-
-xmldom@0.1.x:
- version "0.1.31"
- resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
- integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
-
-xmlhttprequest-ssl@~1.5.4:
- version "1.5.5"
- resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
- integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=
-
-"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@~4.0.0, xtend@~4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
-yallist@^2.1.2:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
- integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
-
yallist@^4.0.0:
version "4.0.0"
- resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yargs-parser@^20.2.3:
- version "20.2.7"
- resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz"
- integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==
-
-yauzl@^2.10.0:
- version "2.10.0"
- resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9"
- integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
- dependencies:
- buffer-crc32 "~0.2.3"
- fd-slicer "~1.1.0"
-
-yeast@0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
- integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
-
-yeoman-environment@^1.5.2:
- version "1.6.6"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-1.6.6.tgz#cd85fa67d156060e440d7807d7ef7cf0d2d1d671"
- integrity sha1-zYX6Z9FWBg5EDXgH1+988NLR1nE=
- dependencies:
- chalk "^1.0.0"
- debug "^2.0.0"
- diff "^2.1.2"
- escape-string-regexp "^1.0.2"
- globby "^4.0.0"
- grouped-queue "^0.3.0"
- inquirer "^1.0.2"
- lodash "^4.11.1"
- log-symbols "^1.0.1"
- mem-fs "^1.1.0"
- text-table "^0.2.0"
- untildify "^2.0.0"
-
-yeoman-environment@^2.0.5, yeoman-environment@^2.9.5:
- version "2.10.3"
- resolved "https://registry.yarnpkg.com/yeoman-environment/-/yeoman-environment-2.10.3.tgz#9d8f42b77317414434cc0e51fb006a4bdd54688e"
- integrity sha512-pLIhhU9z/G+kjOXmJ2bPFm3nejfbH+f1fjYRSOteEXDBrv1EoJE/e+kuHixSXfCYfTkxjYsvRaDX+1QykLCnpQ==
- dependencies:
- chalk "^2.4.1"
- debug "^3.1.0"
- diff "^3.5.0"
- escape-string-regexp "^1.0.2"
- execa "^4.0.0"
- globby "^8.0.1"
- grouped-queue "^1.1.0"
- inquirer "^7.1.0"
- is-scoped "^1.0.0"
- lodash "^4.17.10"
- log-symbols "^2.2.0"
- mem-fs "^1.1.0"
- mem-fs-editor "^6.0.0"
- npm-api "^1.0.0"
- semver "^7.1.3"
- strip-ansi "^4.0.0"
- text-table "^0.2.0"
- untildify "^3.0.3"
- yeoman-generator "^4.8.2"
-
-yeoman-generator@^3.1.1:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-3.2.0.tgz#02077d2d7ff28fedc1ed7dad7f9967fd7c3604cc"
- integrity sha512-iR/qb2je3GdXtSfxgvOXxUW0Cp8+C6LaZaNlK2BAICzFNzwHtM10t/QBwz5Ea9nk6xVDQNj4Q889TjCXGuIv8w==
- dependencies:
- async "^2.6.0"
- chalk "^2.3.0"
- cli-table "^0.3.1"
- cross-spawn "^6.0.5"
- dargs "^6.0.0"
- dateformat "^3.0.3"
- debug "^4.1.0"
- detect-conflict "^1.0.0"
- error "^7.0.2"
- find-up "^3.0.0"
- github-username "^4.0.0"
- istextorbinary "^2.2.1"
- lodash "^4.17.10"
- make-dir "^1.1.0"
- mem-fs-editor "^5.0.0"
- minimist "^1.2.0"
- pretty-bytes "^5.1.0"
- read-chunk "^3.0.0"
- read-pkg-up "^4.0.0"
- rimraf "^2.6.2"
- run-async "^2.0.0"
- shelljs "^0.8.0"
- text-table "^0.2.0"
- through2 "^3.0.0"
- yeoman-environment "^2.0.5"
-
-yeoman-generator@^4.8.2:
- version "4.13.0"
- resolved "https://registry.yarnpkg.com/yeoman-generator/-/yeoman-generator-4.13.0.tgz#a6caeed8491fceea1f84f53e31795f25888b4672"
- integrity sha512-f2/5N5IR3M2Ozm+QocvZQudlQITv2DwI6Mcxfy7R7gTTzaKgvUpgo/pQMJ+WQKm0KN0YMWCFOZpj0xFGxevc1w==
- dependencies:
- async "^2.6.2"
- chalk "^2.4.2"
- cli-table "^0.3.1"
- cross-spawn "^6.0.5"
- dargs "^6.1.0"
- dateformat "^3.0.3"
- debug "^4.1.1"
- diff "^4.0.1"
- error "^7.0.2"
- find-up "^3.0.0"
- github-username "^3.0.0"
- istextorbinary "^2.5.1"
- lodash "^4.17.11"
- make-dir "^3.0.0"
- mem-fs-editor "^7.0.1"
- minimist "^1.2.5"
- pretty-bytes "^5.2.0"
- read-chunk "^3.2.0"
- read-pkg-up "^5.0.0"
- rimraf "^2.6.3"
- run-async "^2.0.0"
- semver "^7.2.1"
- shelljs "^0.8.4"
- text-table "^0.2.0"
- through2 "^3.0.1"
- optionalDependencies:
- grouped-queue "^1.1.0"
- yeoman-environment "^2.9.5"
-
-zip-stream@^2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-2.1.3.tgz#26cc4bdb93641a8590dd07112e1f77af1758865b"
- integrity sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==
- dependencies:
- archiver-utils "^2.1.0"
- compress-commons "^2.1.1"
- readable-stream "^3.4.0"
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==