summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--BUILD41
-rw-r--r--Documentation/cmd-close-connection.txt2
-rw-r--r--Documentation/cmd-create-account.txt2
-rw-r--r--Documentation/cmd-create-branch.txt4
-rw-r--r--Documentation/cmd-create-group.txt4
-rw-r--r--Documentation/cmd-create-project.txt26
-rw-r--r--Documentation/cmd-flush-caches.txt28
-rw-r--r--Documentation/cmd-gc.txt20
-rw-r--r--Documentation/cmd-gsql.txt20
-rw-r--r--Documentation/cmd-hook-commit-msg.txt30
-rw-r--r--Documentation/cmd-index-activate.txt4
-rw-r--r--Documentation/cmd-index-changes-in-project.txt2
-rw-r--r--Documentation/cmd-index-changes.txt2
-rw-r--r--Documentation/cmd-index-start.txt4
-rw-r--r--Documentation/cmd-kill.txt2
-rw-r--r--Documentation/cmd-logging-ls-level.txt9
-rw-r--r--Documentation/cmd-logging-set-level.txt10
-rw-r--r--Documentation/cmd-ls-groups.txt44
-rw-r--r--Documentation/cmd-ls-members.txt16
-rw-r--r--Documentation/cmd-ls-projects.txt38
-rw-r--r--Documentation/cmd-ls-user-refs.txt4
-rw-r--r--Documentation/cmd-plugin-enable.txt2
-rw-r--r--Documentation/concept-changes.txt6
-rw-r--r--Documentation/config-gerrit.txt5
-rw-r--r--Documentation/dev-bazel.txt26
-rw-r--r--Documentation/metrics.txt7
-rw-r--r--Documentation/rest-api-projects.txt8
-rw-r--r--Documentation/user-search.txt6
-rw-r--r--WORKSPACE50
-rw-r--r--java/com/google/gerrit/acceptance/AbstractDaemonTest.java6
-rw-r--r--java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java21
-rw-r--r--java/com/google/gerrit/acceptance/SshdModule.java41
-rw-r--r--java/com/google/gerrit/acceptance/TestProjectInput.java4
-rw-r--r--java/com/google/gerrit/asciidoctor/DocIndexer.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java37
-rw-r--r--java/com/google/gerrit/elasticsearch/BUILD1
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java2
-rw-r--r--java/com/google/gerrit/extensions/api/projects/ProjectInput.java2
-rw-r--r--java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java4
-rw-r--r--java/com/google/gerrit/lucene/AbstractLuceneIndex.java28
-rw-r--r--java/com/google/gerrit/lucene/AutoCommitWriter.java42
-rw-r--r--java/com/google/gerrit/lucene/GerritIndexWriterConfig.java2
-rw-r--r--java/com/google/gerrit/lucene/QueryBuilder.java14
-rw-r--r--java/com/google/gerrit/lucene/WrappableSearcherManager.java8
-rw-r--r--java/com/google/gerrit/server/StarredChangesUtil.java84
-rw-r--r--java/com/google/gerrit/server/config/ConfigUpdatedEvent.java4
-rw-r--r--java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java6
-rw-r--r--java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java22
-rw-r--r--java/com/google/gerrit/server/git/receive/ReceiveCommits.java13
-rw-r--r--java/com/google/gerrit/server/index/account/AccountSchemaDefinitions.java4
-rw-r--r--java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java5
-rw-r--r--java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java5
-rw-r--r--java/com/google/gerrit/server/logging/TraceContext.java20
-rw-r--r--java/com/google/gerrit/server/permissions/PermissionCollection.java76
-rw-r--r--java/com/google/gerrit/server/project/CreateProjectArgs.java4
-rw-r--r--java/com/google/gerrit/server/project/ProjectState.java36
-rw-r--r--java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java15
-rw-r--r--java/com/google/gerrit/server/restapi/config/GetServerInfo.java20
-rw-r--r--java/com/google/gerrit/server/restapi/project/CreateProject.java6
-rw-r--r--java/com/google/gerrit/server/restapi/project/Module.java4
-rw-r--r--java/com/google/gerrit/server/restapi/project/ProjectsCollection.java5
-rw-r--r--java/com/google/gerrit/server/restapi/project/SetParent.java26
-rw-r--r--java/com/google/gerrit/sshd/AliasCommand.java2
-rw-r--r--java/com/google/gerrit/sshd/AliasCommandProvider.java2
-rw-r--r--java/com/google/gerrit/sshd/BaseCommand.java2
-rw-r--r--java/com/google/gerrit/sshd/CommandFactoryProvider.java4
-rw-r--r--java/com/google/gerrit/sshd/CommandModule.java2
-rw-r--r--java/com/google/gerrit/sshd/CommandProvider.java2
-rw-r--r--java/com/google/gerrit/sshd/Commands.java2
-rw-r--r--java/com/google/gerrit/sshd/DispatchCommand.java2
-rw-r--r--java/com/google/gerrit/sshd/DispatchCommandProvider.java2
-rw-r--r--java/com/google/gerrit/sshd/NoShell.java2
-rw-r--r--java/com/google/gerrit/sshd/PluginCommandModule.java2
-rw-r--r--java/com/google/gerrit/sshd/SingleCommandPluginModule.java2
-rw-r--r--java/com/google/gerrit/sshd/SshAutoRegisterModuleGenerator.java2
-rw-r--r--java/com/google/gerrit/sshd/SshDaemon.java4
-rw-r--r--java/com/google/gerrit/sshd/SshLog.java22
-rw-r--r--java/com/google/gerrit/sshd/SshModule.java2
-rw-r--r--java/com/google/gerrit/sshd/SshPluginStarterCallback.java2
-rw-r--r--java/com/google/gerrit/sshd/SuExec.java2
-rw-r--r--java/com/google/gerrit/sshd/commands/CloseConnection.java2
-rw-r--r--javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java10
-rw-r--r--javatests/com/google/gerrit/server/permissions/RefControlTest.java5
-rw-r--r--javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java47
-rw-r--r--lib/mina/BUILD1
-rw-r--r--lib/polymer_externs/BUILD9
-rw-r--r--polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html49
-rw-r--r--polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js132
-rw-r--r--polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html132
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js16
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html14
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html51
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html4
-rw-r--r--polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js4
-rw-r--r--polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html13
-rw-r--r--polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js55
-rw-r--r--polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html67
-rw-r--r--polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html74
-rw-r--r--polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html51
-rw-r--r--polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html2
-rw-r--r--polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js16
-rw-r--r--polygerrit-ui/app/styles/themes/dark-theme.html4
-rw-r--r--tools/bzl/junit.bzl17
-rwxr-xr-xtools/eclipse/project.py12
109 files changed, 1269 insertions, 579 deletions
diff --git a/BUILD b/BUILD
index 4bba5a5cf7..d924417c08 100644
--- a/BUILD
+++ b/BUILD
@@ -2,6 +2,10 @@ package(default_visibility = ["//visibility:public"])
load("//tools/bzl:genrule2.bzl", "genrule2")
load("//tools/bzl:pkg_war.bzl", "pkg_war")
+load(
+ "@bazel_tools//tools/jdk:default_java_toolchain.bzl",
+ "default_java_toolchain",
+)
config_setting(
name = "java9",
@@ -10,6 +14,43 @@ config_setting(
},
)
+config_setting(
+ name = "java10",
+ values = {
+ "java_toolchain": ":toolchain_vanilla",
+ },
+)
+
+# TODO(davido): Switch to consuming it from @bazel_tool//tools/jdk:absolute_javabase
+# when new Bazel version is released with this change included:
+# https://github.com/bazelbuild/bazel/issues/6012
+# https://github.com/bazelbuild/bazel/commit/0173bdbf7bdd1874379d4dd3eb70d5321e0f1816
+# As the interim use a hack that works around it by putting the variable reference
+# behind a select
+config_setting(
+ name = "use_absolute_javabase",
+ values = {"define": "USE_ABSOLUTE_JAVABASE=true"},
+)
+
+java_runtime(
+ name = "absolute_javabase",
+ java_home = select({
+ ":use_absolute_javabase": "$(ABSOLUTE_JAVABASE)",
+ "//conditions:default": "",
+ }),
+ visibility = ["//visibility:public"],
+)
+
+# TODO(davido): Switch to consuming it from @bazel_tool//tools/jdk:toolchain_vanilla
+# when my change is included in released Bazel version:
+# https://github.com/bazelbuild/bazel/commit/0bef68e054eccecd690e5d9f46db8a0c4b2d887a
+default_java_toolchain(
+ name = "toolchain_vanilla",
+ forcibly_disable_header_compilation = True,
+ javabuilder = ["@bazel_tools//tools/jdk:VanillaJavaBuilder_deploy.jar"],
+ jvm_opts = [],
+)
+
genrule(
name = "gen_version",
outs = ["version.txt"],
diff --git a/Documentation/cmd-close-connection.txt b/Documentation/cmd-close-connection.txt
index 973441e294..c161541e41 100644
--- a/Documentation/cmd-close-connection.txt
+++ b/Documentation/cmd-close-connection.txt
@@ -1,7 +1,7 @@
= gerrit close-connection
== NAME
-gerrit close-connection - Close the specified SSH connection
+gerrit close-connection - Close the specified SSH connection.
== SYNOPSIS
[verse]
diff --git a/Documentation/cmd-create-account.txt b/Documentation/cmd-create-account.txt
index 62bd0aa328..617191fb6d 100644
--- a/Documentation/cmd-create-account.txt
+++ b/Documentation/cmd-create-account.txt
@@ -69,7 +69,7 @@ Create a new batch/role access user account called `watcher` in
the 'Non-Interactive Users' group.
----
- $ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit create-account --group "'Non-Interactive Users'" --ssh-key - watcher
+$ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit create-account --group "'Non-Interactive Users'" --ssh-key - watcher
----
GERRIT
diff --git a/Documentation/cmd-create-branch.txt b/Documentation/cmd-create-branch.txt
index 336af56d11..2060917d8c 100644
--- a/Documentation/cmd-create-branch.txt
+++ b/Documentation/cmd-create-branch.txt
@@ -1,7 +1,7 @@
= gerrit create-branch
== NAME
-gerrit create-branch - Create a new branch
+gerrit create-branch - Create a new branch.
== SYNOPSIS
[verse]
@@ -40,7 +40,7 @@ Create a new branch called 'newbranch' from the 'master' branch of
the project 'myproject'.
----
- $ ssh -p 29418 review.example.com gerrit create-branch myproject newbranch master
+$ ssh -p 29418 review.example.com gerrit create-branch myproject newbranch master
----
GERRIT
diff --git a/Documentation/cmd-create-group.txt b/Documentation/cmd-create-group.txt
index 7f1f463dea..2ba611c0ea 100644
--- a/Documentation/cmd-create-group.txt
+++ b/Documentation/cmd-create-group.txt
@@ -68,14 +68,14 @@ Create a new account group called `gerritdev` with two initial members
`developer1` and `developer2`. The group should be owned by itself:
----
- $ ssh -p 29418 user@review.example.com gerrit create-group --member developer1 --member developer2 gerritdev
+$ ssh -p 29418 user@review.example.com gerrit create-group --member developer1 --member developer2 gerritdev
----
Create a new account group called `Foo` owned by the `Foo-admin` group.
Put `developer1` as the initial member and include group description:
----
- $ ssh -p 29418 user@review.example.com gerrit create-group --owner Foo-admin --member developer1 --description "'Foo description'" Foo
+$ ssh -p 29418 user@review.example.com gerrit create-group --owner Foo-admin --member developer1 --description "'Foo description'" Foo
----
Note that it is necessary to quote the description twice. The local
diff --git a/Documentation/cmd-create-project.txt b/Documentation/cmd-create-project.txt
index e8c3857b60..026d7b1f5a 100644
--- a/Documentation/cmd-create-project.txt
+++ b/Documentation/cmd-create-project.txt
@@ -1,7 +1,7 @@
= gerrit create-project
== NAME
-gerrit create-project - Create a new hosted project
+gerrit create-project - Create a new hosted project.
== SYNOPSIS
[verse]
@@ -61,15 +61,17 @@ This command is intended to be used in scripts.
--owner::
-o::
Identifier of the group(s) which will initially own this repository.
++
+--
+This can be:
- This can be:
-
- * the UUID of the group
- * the legacy numeric ID of the group
- * the name of the group if it is unique
-
- The specified group(s) must already be defined within Gerrit.
- Several groups can be specified on the command line.
+* the UUID of the group
+* the legacy numeric ID of the group
+* the name of the group if it is unique
+--
++
+The specified group(s) must already be defined within Gerrit.
+Several groups can be specified on the command line.
+
Defaults to what is specified by `repository.*.ownerGroup`
in gerrit.config.
@@ -180,13 +182,13 @@ Common unit suffixes of 'k', 'm', or 'g' are supported.
Create a new project called `tools/gerrit`:
----
- $ ssh -p 29418 review.example.com gerrit create-project tools/gerrit.git
+$ ssh -p 29418 review.example.com gerrit create-project tools/gerrit.git
----
Create a new project with a description:
----
- $ ssh -p 29418 review.example.com gerrit create-project tool.git --description "'Tools used by build system'"
+$ ssh -p 29418 review.example.com gerrit create-project tool.git --description "'Tools used by build system'"
----
Note that it is necessary to quote the description twice. The local
@@ -199,7 +201,7 @@ If the replication plugin is installed, the plugin will attempt to
perform remote repository creation by a Bourne shell script:
----
- mkdir -p '/base/project.git' && cd '/base/project.git' && git init --bare && git update-ref HEAD refs/heads/master
+mkdir -p '/base/project.git' && cd '/base/project.git' && git init --bare && git update-ref HEAD refs/heads/master
----
For this to work successfully the remote system must be able to run
diff --git a/Documentation/cmd-flush-caches.txt b/Documentation/cmd-flush-caches.txt
index 9ba4808a1d..55d9083178 100644
--- a/Documentation/cmd-flush-caches.txt
+++ b/Documentation/cmd-flush-caches.txt
@@ -1,7 +1,7 @@
= gerrit flush-caches
== NAME
-gerrit flush-caches - Flush some/all server caches from memory
+gerrit flush-caches - Flush some/all server caches from memory.
== SYNOPSIS
[verse]
@@ -58,40 +58,40 @@ This command is intended to be used in scripts.
List caches available for flushing:
----
- $ ssh -p 29418 review.example.com gerrit flush-caches --list
- accounts
- diff
- groups
- ldap_groups
- openid
- projects
- sshkeys
- web_sessions
+$ ssh -p 29418 review.example.com gerrit flush-caches --list
+accounts
+diff
+groups
+ldap_groups
+openid
+projects
+sshkeys
+web_sessions
----
Flush all caches known to the server, forcing them to recompute:
----
- $ ssh -p 29418 review.example.com gerrit flush-caches --all
+$ ssh -p 29418 review.example.com gerrit flush-caches --all
----
or
----
- $ ssh -p 29418 review.example.com gerrit flush-caches
+$ ssh -p 29418 review.example.com gerrit flush-caches
----
Flush only the "sshkeys" cache, after manually editing an SSH key
for a user:
----
- $ ssh -p 29418 review.example.com gerrit flush-caches --cache sshkeys
+$ ssh -p 29418 review.example.com gerrit flush-caches --cache sshkeys
----
Flush "web_sessions", forcing all users to sign-in again:
----
- $ ssh -p 29418 review.example.com gerrit flush-caches --cache web_sessions
+$ ssh -p 29418 review.example.com gerrit flush-caches --cache web_sessions
----
== SEE ALSO
diff --git a/Documentation/cmd-gc.txt b/Documentation/cmd-gc.txt
index 1d1cc002b9..390dce18d0 100644
--- a/Documentation/cmd-gc.txt
+++ b/Documentation/cmd-gc.txt
@@ -1,7 +1,7 @@
= gerrit gc
== NAME
-gerrit gc - Run the Git garbage collection
+gerrit gc - Run the Git garbage collection.
== SYNOPSIS
[verse]
@@ -54,19 +54,19 @@ This command is intended to be used in scripts.
Run the Git garbage collection for the projects 'myProject' and
'yourProject':
----
- $ ssh -p 29418 review.example.com gerrit gc myProject yourProject
- collecting garbage for "myProject":
- ...
- done.
-
- collecting garbage for "yourProject":
- ...
- done.
+$ ssh -p 29418 review.example.com gerrit gc myProject yourProject
+collecting garbage for "myProject":
+...
+done.
+
+collecting garbage for "yourProject":
+...
+done.
----
Run the Git garbage collection for all projects:
----
- $ ssh -p 29418 review.example.com gerrit gc --all
+$ ssh -p 29418 review.example.com gerrit gc --all
----
GERRIT
diff --git a/Documentation/cmd-gsql.txt b/Documentation/cmd-gsql.txt
index d2eb7833c4..7f2aaf7b78 100644
--- a/Documentation/cmd-gsql.txt
+++ b/Documentation/cmd-gsql.txt
@@ -1,7 +1,7 @@
= gerrit gsql
== NAME
-gerrit gsql - Administrative interface to active database
+gerrit gsql - Administrative interface to active database.
== SYNOPSIS
[verse]
@@ -42,18 +42,18 @@ JSON_SINGLE.
To manually correct a user's SSH user name:
----
- $ ssh -p 29418 review.example.com gerrit gsql
- Welcome to Gerrit Code Review v2.0.25
- (PostgreSQL 8.3.8)
+$ ssh -p 29418 review.example.com gerrit gsql
+Welcome to Gerrit Code Review v2.0.25
+(PostgreSQL 8.3.8)
- Type '\h' for help. Type '\r' to clear the buffer.
+Type '\h' for help. Type '\r' to clear the buffer.
- gerrit> update accounts set ssh_user_name = 'alice' where account_id=1;
- UPDATE 1; 1 ms
- gerrit> \q
- Bye
+gerrit> update accounts set ssh_user_name = 'alice' where account_id=1;
+UPDATE 1; 1 ms
+gerrit> \q
+Bye
- $ ssh -p 29418 review.example.com gerrit flush-caches --cache sshkeys --cache accounts
+$ ssh -p 29418 review.example.com gerrit flush-caches --cache sshkeys --cache accounts
----
GERRIT
diff --git a/Documentation/cmd-hook-commit-msg.txt b/Documentation/cmd-hook-commit-msg.txt
index ffdd5da05a..49d5c173be 100644
--- a/Documentation/cmd-hook-commit-msg.txt
+++ b/Documentation/cmd-hook-commit-msg.txt
@@ -20,24 +20,24 @@ After the hook has been installed in the user's local Git repository
for a project, the hook will modify a commit message such as:
----
- Improve foo widget by attaching a bar.
+Improve foo widget by attaching a bar.
- We want a bar, because it improves the foo by providing more
- wizbangery to the dowhatimeanery.
+We want a bar, because it improves the foo by providing more
+wizbangery to the dowhatimeanery.
- Signed-off-by: A. U. Thor <author@example.com>
+Signed-off-by: A. U. Thor <author@example.com>
----
by inserting a new `Change-Id: ` line in the footer:
----
- Improve foo widget by attaching a bar.
+Improve foo widget by attaching a bar.
- We want a bar, because it improves the foo by providing more
- wizbangery to the dowhatimeanery.
+We want a bar, because it improves the foo by providing more
+wizbangery to the dowhatimeanery.
- Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b
- Signed-off-by: A. U. Thor <author@example.com>
+Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b
+Signed-off-by: A. U. Thor <author@example.com>
----
The hook implementation is reasonably intelligent at inserting the
@@ -57,31 +57,29 @@ to `false` in the git config.
== OBTAINING
-
To obtain the `commit-msg` script use `scp`, `wget` or `curl` to download
it to your local system from your Gerrit server.
You can use either of the below commands:
----
- $ scp -p -P 29418 <your username>@<your Gerrit review server>:hooks/commit-msg <local path to your git>/.git/hooks/
+$ scp -p -P 29418 <your username>@<your Gerrit review server>:hooks/commit-msg <local path to your git>/.git/hooks/
- $ curl -Lo <local path to your git>/.git/hooks/commit-msg <your Gerrit http URL>/tools/hooks/commit-msg
+$ curl -Lo <local path to your git>/.git/hooks/commit-msg <your Gerrit http URL>/tools/hooks/commit-msg
----
A specific example of this might look something like this:
-.Example
----
- $ scp -p -P 29418 john.doe@review.example.com:hooks/commit-msg ~/duhproject/.git/hooks/
+$ scp -p -P 29418 john.doe@review.example.com:hooks/commit-msg ~/duhproject/.git/hooks/
- $ curl -Lo ~/duhproject/.git/hooks/commit-msg http://review.example.com/tools/hooks/commit-msg
+$ curl -Lo ~/duhproject/.git/hooks/commit-msg http://review.example.com/tools/hooks/commit-msg
----
Make sure the hook file is executable:
----
- $ chmod u+x ~/duhproject/.git/hooks/commit-msg
+$ chmod u+x ~/duhproject/.git/hooks/commit-msg
----
== SEE ALSO
diff --git a/Documentation/cmd-index-activate.txt b/Documentation/cmd-index-activate.txt
index 4428d12708..0bbf308494 100644
--- a/Documentation/cmd-index-activate.txt
+++ b/Documentation/cmd-index-activate.txt
@@ -1,7 +1,7 @@
= gerrit index activate
== NAME
-gerrit index activate - Activate the latest index version available
+gerrit index activate - Activate the latest index version available.
== SYNOPSIS
[verse]
@@ -37,7 +37,7 @@ This command is intended to be used in scripts.
Activate the latest change index:
----
- $ ssh -p 29418 review.example.com gerrit index activate changes
+$ ssh -p 29418 review.example.com gerrit index activate changes
----
GERRIT
diff --git a/Documentation/cmd-index-changes-in-project.txt b/Documentation/cmd-index-changes-in-project.txt
index ec1626f29e..b2282fc939 100644
--- a/Documentation/cmd-index-changes-in-project.txt
+++ b/Documentation/cmd-index-changes-in-project.txt
@@ -26,7 +26,7 @@ This command is intended to be used in scripts.
Index all changes in projects MyProject and NiceProject.
----
- $ ssh -p 29418 user@review.example.com gerrit index changes-in-project MyProject NiceProject
+$ ssh -p 29418 user@review.example.com gerrit index changes-in-project MyProject NiceProject
----
GERRIT
diff --git a/Documentation/cmd-index-changes.txt b/Documentation/cmd-index-changes.txt
index d38c51ad4a..0ee7aabd26 100644
--- a/Documentation/cmd-index-changes.txt
+++ b/Documentation/cmd-index-changes.txt
@@ -30,7 +30,7 @@ This command is intended to be used in scripts.
Index changes with legacy ID numbers 1 and 2.
----
- $ ssh -p 29418 user@review.example.com gerrit index changes 1 2
+$ ssh -p 29418 user@review.example.com gerrit index changes 1 2
----
GERRIT
diff --git a/Documentation/cmd-index-start.txt b/Documentation/cmd-index-start.txt
index 5a002f397d..d1a02b362f 100644
--- a/Documentation/cmd-index-start.txt
+++ b/Documentation/cmd-index-start.txt
@@ -1,7 +1,7 @@
= gerrit index start
== NAME
-gerrit index start - Start the online indexer
+gerrit index start - Start the online indexer.
== SYNOPSIS
[verse]
@@ -44,7 +44,7 @@ This command is intended to be used in scripts.
Start the online indexer for the 'changes' index:
----
- $ ssh -p 29418 review.example.com gerrit index start changes
+$ ssh -p 29418 review.example.com gerrit index start changes
----
GERRIT
diff --git a/Documentation/cmd-kill.txt b/Documentation/cmd-kill.txt
index ac8e8028a3..db5093d221 100644
--- a/Documentation/cmd-kill.txt
+++ b/Documentation/cmd-kill.txt
@@ -1,7 +1,7 @@
= kill
== NAME
-kill - Cancel or abort a background task
+kill - Cancel or abort a background task.
== SYNOPSIS
[verse]
diff --git a/Documentation/cmd-logging-ls-level.txt b/Documentation/cmd-logging-ls-level.txt
index ee015bb0de..fb1fb33efd 100644
--- a/Documentation/cmd-logging-ls-level.txt
+++ b/Documentation/cmd-logging-ls-level.txt
@@ -1,9 +1,9 @@
= gerrit logging ls-level
== NAME
-gerrit logging ls-level - view the logging level
+gerrit logging ls-level - view the logging level.
-gerrit logging ls - view the logging level
+gerrit logging ls - view the logging level.
== SYNOPSIS
[verse]
@@ -27,13 +27,12 @@ Caller must have the ADMINISTRATE_SERVER capability.
View the logging level of the loggers in the package com.google:
----
- $ssh -p 29418 review.example.com gerrit logging ls-level \
- com.google.
+$ssh -p 29418 review.example.com gerrit logging ls-level com.google.
----
View the logging level of every logger
----
- $ssh -p 29418 review.example.com gerrit logging ls-level
+$ssh -p 29418 review.example.com gerrit logging ls-level
----
GERRIT
diff --git a/Documentation/cmd-logging-set-level.txt b/Documentation/cmd-logging-set-level.txt
index 5baa9687c4..d7fc69e1bc 100644
--- a/Documentation/cmd-logging-set-level.txt
+++ b/Documentation/cmd-logging-set-level.txt
@@ -1,9 +1,9 @@
= gerrit logging set-level
== NAME
-gerrit logging set-level - set the logging level
+gerrit logging set-level - set the logging level.
-gerrit logging set - set the logging level
+gerrit logging set - set the logging level.
== SYNOPSIS
[verse]
@@ -34,14 +34,12 @@ Caller must have the ADMINISTRATE_SERVER capability.
Change the logging level of the loggers in the package com.google to DEBUG.
----
- $ssh -p 29418 review.example.com gerrit logging set-level \
- debug com.google.
+$ssh -p 29418 review.example.com gerrit logging set-level debug com.google.
----
Reset the logging level of every logger to what they were at deployment time.
----
- $ssh -p 29418 review.example.com gerrit logging set-level \
- reset
+$ssh -p 29418 review.example.com gerrit logging set-level reset
----
GERRIT
diff --git a/Documentation/cmd-ls-groups.txt b/Documentation/cmd-ls-groups.txt
index 6d4bdc5374..8a4845c263 100644
--- a/Documentation/cmd-ls-groups.txt
+++ b/Documentation/cmd-ls-groups.txt
@@ -1,7 +1,7 @@
= gerrit ls-groups
== NAME
-gerrit ls-groups - List groups visible to caller
+gerrit ls-groups - List groups visible to caller.
== SYNOPSIS
[verse]
@@ -88,53 +88,53 @@ nonexistent group, the owner group name field will read `n/a`.
List visible groups:
----
- $ ssh -p 29418 review.example.com gerrit ls-groups
- Administrators
- Anonymous Users
- MyProject_Committers
- Project Owners
- Registered Users
+$ ssh -p 29418 review.example.com gerrit ls-groups
+Administrators
+Anonymous Users
+MyProject_Committers
+Project Owners
+Registered Users
----
List all groups for which any permission is set for the project
"MyProject":
----
- $ ssh -p 29418 review.example.com gerrit ls-groups --project MyProject
- MyProject_Committers
- Project Owners
- Registered Users
+$ ssh -p 29418 review.example.com gerrit ls-groups --project MyProject
+MyProject_Committers
+Project Owners
+Registered Users
----
List all groups which are owned by the calling user:
----
- $ ssh -p 29418 review.example.com gerrit ls-groups --owned
- MyProject_Committers
- MyProject_Verifiers
+$ ssh -p 29418 review.example.com gerrit ls-groups --owned
+MyProject_Committers
+MyProject_Verifiers
----
Check if the calling user owns the group `MyProject_Committers`. If
`MyProject_Committers` is returned the calling user owns this group.
If the result is empty, the calling user doesn't own the group.
----
- $ ssh -p 29418 review.example.com gerrit ls-groups --owned -q MyProject_Committers
- MyProject_Committers
+$ ssh -p 29418 review.example.com gerrit ls-groups --owned -q MyProject_Committers
+MyProject_Committers
----
Extract the UUID of the 'Administrators' group:
----
- $ ssh -p 29418 review.example.com gerrit ls-groups -v | awk '-F\t' '$1 == "Administrators" {print $2}'
- ad463411db3eec4e1efb0d73f55183c1db2fd82a
+$ ssh -p 29418 review.example.com gerrit ls-groups -v | awk '-F\t' '$1 == "Administrators" {print $2}'
+ad463411db3eec4e1efb0d73f55183c1db2fd82a
----
Extract and expand the multi-line description of the 'Administrators'
group:
----
- $ printf "$(ssh -p 29418 review.example.com gerrit ls-groups -v | awk '-F\t' '$1 == "Administrators" {print $3}')\n"
- This is a
- multi-line
- description.
+$ printf "$(ssh -p 29418 review.example.com gerrit ls-groups -v | awk '-F\t' '$1 == "Administrators" {print $3}')\n"
+This is a
+multi-line
+description.
----
GERRIT
diff --git a/Documentation/cmd-ls-members.txt b/Documentation/cmd-ls-members.txt
index 273451ba04..8f8857c5bb 100644
--- a/Documentation/cmd-ls-members.txt
+++ b/Documentation/cmd-ls-members.txt
@@ -1,7 +1,7 @@
= gerrit ls-members
== NAME
-gerrit ls-members - Show members of a given group
+gerrit ls-members - Show members of a given group.
== SYNOPSIS
[verse]
@@ -40,17 +40,17 @@ the output.
List members of the Administrators group:
----
- $ ssh -p 29418 review.example.com gerrit ls-members Administrators
- id username full name email
- 100000 jim Jim Bob somebody@example.com
- 100001 johnny John Smith n/a
- 100002 mrnoname n/a someoneelse@example.com
+$ ssh -p 29418 review.example.com gerrit ls-members Administrators
+id username full name email
+100000 jim Jim Bob somebody@example.com
+100001 johnny John Smith n/a
+100002 mrnoname n/a someoneelse@example.com
----
List members of a non-existent group:
----
- $ ssh -p 29418 review.example.com gerrit ls-members BadlySpelledGroup
- Group not found or not visible
+$ ssh -p 29418 review.example.com gerrit ls-members BadlySpelledGroup
+Group not found or not visible
----
GERRIT
diff --git a/Documentation/cmd-ls-projects.txt b/Documentation/cmd-ls-projects.txt
index 486ca44aab..3bb8e4f597 100644
--- a/Documentation/cmd-ls-projects.txt
+++ b/Documentation/cmd-ls-projects.txt
@@ -1,7 +1,7 @@
= gerrit ls-projects
== NAME
-gerrit ls-projects - List projects visible to caller
+gerrit ls-projects - List projects visible to caller.
== SYNOPSIS
[verse]
@@ -115,28 +115,28 @@ by the client in the request headers.
List visible projects:
----
- $ ssh -p 29418 review.example.com gerrit ls-projects
- platform/manifest
- tools/gerrit
- tools/gwtorm
-
- $ curl http://review.example.com/projects/
- platform/manifest
- tools/gerrit
- tools/gwtorm
-
- $ curl http://review.example.com/projects/tools/
- tools/gerrit
- tools/gwtorm
+$ ssh -p 29418 review.example.com gerrit ls-projects
+platform/manifest
+tools/gerrit
+tools/gwtorm
+
+$ curl http://review.example.com/projects/
+platform/manifest
+tools/gerrit
+tools/gwtorm
+
+$ curl http://review.example.com/projects/tools/
+tools/gerrit
+tools/gwtorm
----
Clone any project visible to the user:
----
- for p in `ssh -p 29418 review.example.com gerrit ls-projects`
- do
- mkdir -p `dirname "$p"`
- git clone --bare "ssh://review.example.com:29418/$p.git" "$p.git"
- done
+for p in `ssh -p 29418 review.example.com gerrit ls-projects`
+do
+ mkdir -p `dirname "$p"`
+ git clone --bare "ssh://review.example.com:29418/$p.git" "$p.git"
+done
----
== SEE ALSO
diff --git a/Documentation/cmd-ls-user-refs.txt b/Documentation/cmd-ls-user-refs.txt
index 1a87fc9507..cba7d1bdef 100644
--- a/Documentation/cmd-ls-user-refs.txt
+++ b/Documentation/cmd-ls-user-refs.txt
@@ -1,7 +1,7 @@
= gerrit ls-user-refs
== NAME
-gerrit ls-user-refs - List refs visible to a specific user
+gerrit ls-user-refs - List refs visible to a specific user.
== SYNOPSIS
[verse]
@@ -42,7 +42,7 @@ Administrators
List visible refs for the user "mr.developer" in project "gerrit"
----
- $ ssh -p 29418 review.example.com gerrit ls-user-refs -p gerrit -u mr.developer
+$ ssh -p 29418 review.example.com gerrit ls-user-refs -p gerrit -u mr.developer
----
GERRIT
diff --git a/Documentation/cmd-plugin-enable.txt b/Documentation/cmd-plugin-enable.txt
index 9b5273630c..955267e88c 100644
--- a/Documentation/cmd-plugin-enable.txt
+++ b/Documentation/cmd-plugin-enable.txt
@@ -32,7 +32,7 @@ This command is intended to be used in scripts.
Enable a plugin:
----
- ssh -p 29418 localhost gerrit plugin enable my-plugin
+ssh -p 29418 localhost gerrit plugin enable my-plugin
----
GERRIT
diff --git a/Documentation/concept-changes.txt b/Documentation/concept-changes.txt
index 7320a508f6..1d275b419a 100644
--- a/Documentation/concept-changes.txt
+++ b/Documentation/concept-changes.txt
@@ -55,7 +55,7 @@ are not required to review it.
|An optional topic.
|Strategy
-|The <<submit-strategy>> for the change.
+|The <<submit-strategies,submit strategy>> for the change.
|Code Review
|Displays the Code Review status for the change.
@@ -84,10 +84,10 @@ listed next to the change message. These related changes are grouped together in
several categories, including:
* Relation Chain. These changes are related by parent-child relationships,
- regardless of <<topics>>.
+ regardless of <<topic,topic>>.
* Merge Conflicts. These are changes in which there is a merge conflict with
the current change.
-* Submitted Together. These are changes that share the same <<topics>>.
+* Submitted Together. These are changes that share the same <<topic,topic>>.
An arrow indicates the change you are currently viewing.
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 734397e877..9f0bf8650e 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -690,7 +690,7 @@ H2 uses memory to cache its database content. The parameter `h2CacheSize`
allows to limit the memory used by H2 and thus prevent out-of-memory
caused by the H2 database using too much memory.
+
-See <<database.h2.cachesize,database.h2.cachesize>> for a detailed discussion.
+See <<database.h2.cacheSize,database.h2.cacheSize>> for a detailed discussion.
+
Default is unset, using up to half of the available memory.
+
@@ -3684,6 +3684,9 @@ allow the owner to circumvent certain enforced rules (like important
BLOCK rules).
+
Default is false.
++
+This value supports configuration reloads:
+link:cmd-reload-config.html[reload-config]
[[receive.checkReferencedObjectsAreReachable]]receive.checkReferencedObjectsAreReachable::
+
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 6331581fc7..0ecc82075c 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -6,7 +6,7 @@
To build Gerrit from source, you need:
* A Linux or macOS system (Windows is not supported at this time)
-* A JDK for Java 8
+* A JDK for Java 8|9|10
* Python 2 or 3
* Node.js
* link:https://www.bazel.io/versions/master/docs/install.html[Bazel]
@@ -14,6 +14,30 @@ To build Gerrit from source, you need:
* zip, unzip
* gcc
+[[Java 10 support]]
+Java 10 is supported through vanilla java toolchain
+link:https://docs.bazel.build/versions/master/toolchains.html[Bazel option].
+To build Gerrit with Java 10, specify vanilla java toolchain and provide
+path to Java 10 home:
+
+```
+ $ bazel build --host_javabase=:absolute_javabase \
+ --define=ABSOLUTE_JAVABASE=<path-to-java-10> \
+ --define=USE_ABSOLUTE_JAVABASE=true \
+ --host_java_toolchain=//:toolchain_vanilla \
+ --java_toolchain=//:toolchain_vanilla \
+ :release
+```
+
+Note that the following options must be added to `container.javaOptions`
+in `$gerrit_site/etc/gerrit.config` to run Gerrit with Java 10:
+
+```
+[container]
+ javaOptions = --add-modules java.activation
+ javaOptions = --add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED
+```
+
[[Java 9 support]]
Java 9 is supported through alternative java toolchain
link:https://docs.bazel.build/versions/master/toolchains.html[Bazel option].
diff --git a/Documentation/metrics.txt b/Documentation/metrics.txt
index 19d3b41fc4..2647b359cf 100644
--- a/Documentation/metrics.txt
+++ b/Documentation/metrics.txt
@@ -138,6 +138,13 @@ failed by table.
* `notedb/read_all_external_ids_latency`: Latency for reading all
external ID's from NoteDb.
+=== Permissions
+
+* `permissions/project_state/computation_latency`: Latency to compute current access
+sections on a project by traversing it's parents.
+* `permissions/permission_collection/filter_latency`: Latency to filter access sections
+by user and ref.
+
=== Reviewer Suggestion
* `reviewer_suggestion/query_accounts`: Latency for querying accounts for
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index b517d3c0d4..2a9dcee018 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -3570,6 +3570,12 @@ Whether the usage of Change-Ids is required for the project (`TRUE`,
`FALSE`, `INHERIT`).
This property is deprecated and will be removed in
a future release.
+|`enable_signed_push` |`INHERIT` if not set|
+Whether signed push validation is enabled on the project (`TRUE`,
+`FALSE`, `INHERIT`).
+|`require_signed_push` |`INHERIT` if not set|
+Whether signed push validation is required on the project (`TRUE`,
+`FALSE`, `INHERIT`).
|`max_object_size_limit` |optional|
Max allowed Git object size for this project.
Common unit suffixes of 'k', 'm', or 'g' are supported.
@@ -3707,8 +3713,6 @@ The path to the `GerritSiteHeader.html` file.
The path to the `GerritSiteFooter.html` file.
|=============================
-----
-
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 41cb380908..7c904f5332 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -166,7 +166,7 @@ Changes occurring in 'PROJECT' or in one of the child projects of
'PROJECT'.
[[repository]]
-repository:'REPOSITORY'::
+repository:'REPOSITORY', repo:'REPOSITORY'::
+
Changes occurring in 'REPOSITORY'. If 'REPOSITORY' starts with `^` it
matches repository names by regular expression. The
@@ -174,12 +174,12 @@ link:http://www.brics.dk/automaton/[dk.brics.automaton
library] is used for evaluation of such patterns.
[[repositories]]
-repositories:'PREFIX'::
+repositories:'PREFIX', repos:'PREFIX'::
+
Changes occurring in repositories starting with 'PREFIX'.
[[parentrepository]]
-parentrepository:'REPOSITORY'::
+parentrepository:'REPOSITORY', parentrepo:'REPOSITORY'::
+
Changes occurring in 'REPOSITORY' or in one of the child repositories of
'REPOSITORY'.
diff --git a/WORKSPACE b/WORKSPACE
index 68d7aeb0ab..a20e0b18f3 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -25,6 +25,7 @@ http_archive(
# https://github.com/google/closure-compiler/blob/master/contrib/externs/polymer-1.0.js
http_file(
name = "polymer_closure",
+ downloaded_file_path = "polymer_closure.js",
sha256 = "5a589bdba674e1fec7188e9251c8624ebf2d4d969beb6635f9148f420d1e08b1",
urls = ["https://raw.githubusercontent.com/google/closure-compiler/775609aad61e14aef289ebec4bfc09ad88877f9e/contrib/externs/polymer-1.0.js"],
)
@@ -107,24 +108,24 @@ maven_jar(
sha1 = "83cd2cd674a217ade95a4bb83a8a14f351f48bd0",
)
-GUICE_VERS = "4.2.0"
+GUICE_VERS = "4.2.1"
maven_jar(
name = "guice-library",
artifact = "com.google.inject:guice:" + GUICE_VERS,
- sha1 = "25e1f4c1d528a1cffabcca0d432f634f3132f6c8",
+ sha1 = "f77dfd89318fe3ff293bafceaa75fbf66e4e4b10",
)
maven_jar(
name = "guice-assistedinject",
artifact = "com.google.inject.extensions:guice-assistedinject:" + GUICE_VERS,
- sha1 = "e7270305960ad7db56f7e30cb9df6be9ff1cfb45",
+ sha1 = "d327e4aee7c96f08cd657c17da231a1f4a8999ac",
)
maven_jar(
name = "guice-servlet",
artifact = "com.google.inject.extensions:guice-servlet:" + GUICE_VERS,
- sha1 = "f57581625c36c148f088d9f52a568d5bdf12c61d",
+ sha1 = "3927e462f923b0c672fdb045c5645bca4beab5c0",
)
maven_jar(
@@ -329,8 +330,8 @@ maven_jar(
maven_jar(
name = "args4j-intern",
- artifact = "args4j:args4j:2.0.29",
- sha1 = "55ca4ddc4e906ffbaec043113b36bb410a3d909e",
+ artifact = "args4j:args4j:2.33",
+ sha1 = "bd87a75374a6d6523de82fef51fc3cfe9baf9fc9",
)
maven_jar(
@@ -636,36 +637,36 @@ maven_jar(
sha1 = "05b6f921f1810bdf90e25471968f741f87168b64",
)
-LUCENE_VERS = "5.5.4"
+LUCENE_VERS = "6.6.5"
maven_jar(
name = "lucene-core",
artifact = "org.apache.lucene:lucene-core:" + LUCENE_VERS,
- sha1 = "ab9c77e75cf142aa6e284b310c8395617bd9b19b",
+ sha1 = "2983f80b1037e098209657b0ca9176827892d0c0",
)
maven_jar(
name = "lucene-analyzers-common",
artifact = "org.apache.lucene:lucene-analyzers-common:" + LUCENE_VERS,
- sha1 = "08ce9d34c8124c80e176e8332ee947480bbb9576",
+ sha1 = "6094f91071d90570b7f5f8ce481d5de7d2d2e9d5",
)
maven_jar(
name = "backward-codecs",
artifact = "org.apache.lucene:lucene-backward-codecs:" + LUCENE_VERS,
- sha1 = "a933f42e758c54c43083398127ea7342b54d8212",
+ sha1 = "460a19e8d1aa7d31e9614cf528a6cb508c9e823d",
)
maven_jar(
name = "lucene-misc",
artifact = "org.apache.lucene:lucene-misc:" + LUCENE_VERS,
- sha1 = "a74388857f73614e528ae44d742c60187cb55a5a",
+ sha1 = "ce3a1b7b6a92b9af30791356a4bd46d1cea6cc1e",
)
maven_jar(
name = "lucene-queryparser",
artifact = "org.apache.lucene:lucene-queryparser:" + LUCENE_VERS,
- sha1 = "8a06fad4675473d98d93b61fea529e3f464bf69e",
+ sha1 = "2db9ca0086a4b8e0b9bc9f08a9b420303168e37c",
)
maven_jar(
@@ -777,13 +778,10 @@ maven_jar(
sha1 = "d0c46320fbc07be3a24eb13a56cee4e3d38e0c75",
)
-# TODO(davido): Remove exlusion of file system provider, when this issue is fixed:
-# https://issues.apache.org/jira/browse/SSHD-736
maven_jar(
name = "sshd",
- artifact = "org.apache.sshd:sshd-core:1.7.0",
- exclude = ["META-INF/services/java.nio.file.spi.FileSystemProvider"],
- sha1 = "2e8b14f6d841b098e46bf407b6fdccab4c19fa41",
+ artifact = "org.apache.sshd:sshd-core:2.0.0",
+ sha1 = "f4275079a2463cfd2bf1548a80e1683288a8e86b",
)
maven_jar(
@@ -794,8 +792,14 @@ maven_jar(
maven_jar(
name = "mina-core",
- artifact = "org.apache.mina:mina-core:2.0.16",
- sha1 = "f720f17643eaa7b0fec07c1d7f6272972c02bba4",
+ artifact = "org.apache.mina:mina-core:2.0.17",
+ sha1 = "7e10ec974760436d931f3e58be507d1957bcc8db",
+)
+
+maven_jar(
+ name = "sshd-mina",
+ artifact = "org.apache.sshd:sshd-mina:2.0.0",
+ sha1 = "50f2669312494f6c1996d8bd0d266c1fca7be6f6",
)
maven_jar(
@@ -1063,14 +1067,14 @@ maven_jar(
maven_jar(
name = "asciidoctor",
- artifact = "org.asciidoctor:asciidoctorj:1.5.6",
- sha1 = "bb757d4b8b0f8438ce2ed781f6688cc6c01d9237",
+ artifact = "org.asciidoctor:asciidoctorj:1.5.7",
+ sha1 = "8e8c1d8fc6144405700dd8df3b177f2801ac5987",
)
maven_jar(
name = "jruby",
- artifact = "org.jruby:jruby-complete:9.1.13.0",
- sha1 = "8903bf42272062e87a7cbc1d98919e0729a9939f",
+ artifact = "org.jruby:jruby-complete:9.1.17.0",
+ sha1 = "76716d529710fc03d1d429b43e3cedd4419f78d4",
)
maven_jar(
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 69d603fa4a..030ec2a528 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -502,6 +502,8 @@ public abstract class AbstractDaemonTest {
in.useSignedOffBy = ann.useSignedOffBy();
in.useContentMerge = ann.useContentMerge();
in.rejectEmptyCommit = ann.rejectEmptyCommit();
+ in.enableSignedPush = ann.enableSignedPush();
+ in.requireSignedPush = ann.requireSignedPush();
} else {
// Defaults should match TestProjectConfig, omitting nullable values.
in.createEmptyCommit = true;
@@ -714,7 +716,7 @@ public abstract class AbstractDaemonTest {
throws Exception {
assertThat(topic).isNotEmpty();
return createCommitAndPush(
- repo, "refs/for/master/" + name(topic), commitMsg, fileName, content);
+ repo, "refs/for/master%topic=" + name(topic), commitMsg, fileName, content);
}
protected PushOneCommit.Result createChange(String subject, String fileName, String content)
@@ -733,7 +735,7 @@ public abstract class AbstractDaemonTest {
String topic)
throws Exception {
PushOneCommit push = pushFactory.create(db, admin.getIdent(), repo, subject, fileName, content);
- return push.to("refs/for/" + branch + "/" + name(topic));
+ return push.to("refs/for/" + branch + "%topic=" + name(topic));
}
protected BranchApi createBranch(Branch.NameKey branch) throws Exception {
diff --git a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
index 83a3874d37..b23b6e65e6 100644
--- a/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
+++ b/java/com/google/gerrit/acceptance/InMemoryTestingDatabaseModule.java
@@ -44,16 +44,12 @@ import com.google.gwtorm.server.OrmRuntimeException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Key;
-import com.google.inject.Provides;
import com.google.inject.ProvisionException;
-import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Providers;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
-import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.eclipse.jgit.lib.Config;
class InMemoryTestingDatabaseModule extends LifecycleModule {
@@ -107,23 +103,8 @@ class InMemoryTestingDatabaseModule extends LifecycleModule {
install(new SchemaModule());
bind(SchemaVersion.class).to(SchemaVersion.C);
- }
-
- @Provides
- @Singleton
- KeyPairProvider createHostKey() {
- return getHostKeys();
- }
- private static SimpleGeneratorHostKeyProvider keys;
-
- private static synchronized KeyPairProvider getHostKeys() {
- if (keys == null) {
- keys = new SimpleGeneratorHostKeyProvider();
- keys.setAlgorithm("RSA");
- keys.loadKeys();
- }
- return keys;
+ install(new SshdModule());
}
static class CreateDatabase implements LifecycleListener {
diff --git a/java/com/google/gerrit/acceptance/SshdModule.java b/java/com/google/gerrit/acceptance/SshdModule.java
new file mode 100644
index 0000000000..185d6e2a3d
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/SshdModule.java
@@ -0,0 +1,41 @@
+// Copyright (C) 2018 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.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+
+public class SshdModule extends AbstractModule {
+
+ @Provides
+ @Singleton
+ KeyPairProvider createHostKey() {
+ return getHostKeys();
+ }
+
+ private static SimpleGeneratorHostKeyProvider keys;
+
+ private static synchronized KeyPairProvider getHostKeys() {
+ if (keys == null) {
+ keys = new SimpleGeneratorHostKeyProvider();
+ keys.setAlgorithm("RSA");
+ keys.loadKeys();
+ }
+ return keys;
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/TestProjectInput.java b/java/com/google/gerrit/acceptance/TestProjectInput.java
index eada6434c2..0a3686b543 100644
--- a/java/com/google/gerrit/acceptance/TestProjectInput.java
+++ b/java/com/google/gerrit/acceptance/TestProjectInput.java
@@ -47,6 +47,10 @@ public @interface TestProjectInput {
InheritableBoolean rejectEmptyCommit() default InheritableBoolean.INHERIT;
+ InheritableBoolean enableSignedPush() default InheritableBoolean.INHERIT;
+
+ InheritableBoolean requireSignedPush() default InheritableBoolean.INHERIT;
+
// Fields specific to acceptance test behavior.
/** Username to use for initial clone, passed to {@link AccountCreator}. */
diff --git a/java/com/google/gerrit/asciidoctor/DocIndexer.java b/java/com/google/gerrit/asciidoctor/DocIndexer.java
index ef3ea3f241..951781157a 100644
--- a/java/com/google/gerrit/asciidoctor/DocIndexer.java
+++ b/java/com/google/gerrit/asciidoctor/DocIndexer.java
@@ -33,8 +33,8 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
+import org.apache.lucene.analysis.CharArraySet;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.analysis.util.CharArraySet;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
diff --git a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 2c1c93a1ba..fec7137094 100644
--- a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.CharStreams;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.QueryBuilder;
import com.google.gerrit.elasticsearch.builders.SearchSourceBuilder;
@@ -160,7 +161,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
@Override
public void delete(K id) throws IOException {
String uri = getURI(type, BULK);
- Response response = postRequest(getDeleteActions(id), uri, getRefreshParam());
+ Response response = postRequest(uri, getDeleteActions(id), getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
@@ -172,10 +173,10 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
public void deleteAll() throws IOException {
// Delete the index, if it exists.
String endpoint = indexName + client.adapter().indicesExistParam();
- Response response = client.get().performRequest(new Request("HEAD", endpoint));
+ Response response = performRequest("HEAD", endpoint);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
- response = client.get().performRequest(new Request("DELETE", indexName));
+ response = performRequest("DELETE", indexName);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
@@ -185,7 +186,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
// Recreate the index.
String indexCreationFields = concatJsonString(getSettings(), getMappings());
- response = performRequest("PUT", indexCreationFields, indexName, Collections.emptyMap());
+ response = performRequest("PUT", indexName, indexCreationFields);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
String error = String.format("Failed to create index %s: %s", indexName, statusCode);
@@ -297,20 +298,36 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
return encodedIndexName + "/" + encodedType + "/" + request;
}
- protected Response postRequest(Object payload, String uri, Map<String, String> params)
+ protected Response postRequest(String uri, Object payload) throws IOException {
+ return performRequest("POST", uri, payload);
+ }
+
+ protected Response postRequest(String uri, Object payload, Map<String, String> params)
throws IOException {
- return performRequest("POST", payload, uri, params);
+ return performRequest("POST", uri, payload, params);
}
private String concatJsonString(String target, String addition) {
return target.substring(0, target.length() - 1) + "," + addition.substring(1);
}
+ private Response performRequest(String method, String uri) throws IOException {
+ return performRequest(method, uri, null);
+ }
+
+ private Response performRequest(String method, String uri, @Nullable Object payload)
+ throws IOException {
+ return performRequest(method, uri, payload, Collections.emptyMap());
+ }
+
private Response performRequest(
- String method, Object payload, String uri, Map<String, String> params) throws IOException {
- Request request = new Request(method, uri);
- String payloadStr = payload instanceof String ? (String) payload : payload.toString();
- request.setEntity(new NStringEntity(payloadStr, ContentType.APPLICATION_JSON));
+ String method, String uri, @Nullable Object payload, Map<String, String> params)
+ throws IOException {
+ Request request = new Request(method, uri.startsWith("/") ? uri : "/" + uri);
+ if (payload != null) {
+ String payloadStr = payload instanceof String ? (String) payload : payload.toString();
+ request.setEntity(new NStringEntity(payloadStr, ContentType.APPLICATION_JSON));
+ }
for (Map.Entry<String, String> entry : params.entrySet()) {
request.addParameter(entry.getKey(), entry.getValue());
}
diff --git a/java/com/google/gerrit/elasticsearch/BUILD b/java/com/google/gerrit/elasticsearch/BUILD
index 31ede79f16..8d23051517 100644
--- a/java/com/google/gerrit/elasticsearch/BUILD
+++ b/java/com/google/gerrit/elasticsearch/BUILD
@@ -3,6 +3,7 @@ java_library(
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
deps = [
+ "//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/index",
"//java/com/google/gerrit/index:query_exception",
diff --git a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index d18af423f5..1b69b6d295 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -79,7 +79,7 @@ public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, Accoun
.add(new UpdateRequest<>(schema, as));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index f6af79f228..d7c8b00039 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -138,7 +138,7 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData>
}
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
index bf6b962304..f694a05482 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
@@ -77,7 +77,7 @@ public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, I
.add(new UpdateRequest<>(schema, group));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
index 623f62c439..8510559791 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
@@ -77,7 +77,7 @@ public class ElasticProjectIndex extends AbstractElasticIndex<Project.NameKey, P
.add(new UpdateRequest<>(schema, projectState));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java b/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
index 8cb69e0179..05fd7a7afc 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
@@ -33,7 +33,7 @@ public class ElasticQueryAdapter {
ElasticQueryAdapter(ElasticVersion version) {
this.ignoreUnmapped = version == ElasticVersion.V2_4;
this.usePostV5Type = version.isV6();
- this.versionDiscoveryUrl = version.isV6() ? "%s*" : "%s*/_aliases";
+ this.versionDiscoveryUrl = version.isV6() ? "/%s*" : "/%s*/_aliases";
switch (version) {
case V5_6:
diff --git a/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java b/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
index 337f2ca882..e9839b7978 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
@@ -106,7 +106,7 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen
private ElasticVersion getVersion() throws ElasticException {
try {
- Response response = client.performRequest(new Request("GET", ""));
+ Response response = client.performRequest(new Request("GET", "/"));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
throw new FailedToGetVersion(statusLine);
diff --git a/java/com/google/gerrit/extensions/api/projects/ProjectInput.java b/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
index b7079ae1ee..e61d316a0a 100644
--- a/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
+++ b/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
@@ -34,6 +34,8 @@ public class ProjectInput {
public InheritableBoolean requireChangeId;
public InheritableBoolean createNewChangeForAllNotInTarget;
public InheritableBoolean rejectEmptyCommit;
+ public InheritableBoolean enableSignedPush;
+ public InheritableBoolean requireSignedPush;
public String maxObjectSizeLimit;
public Map<String, Map<String, ConfigValue>> pluginConfigValues;
}
diff --git a/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
index 07b5adb000..6229041067 100644
--- a/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
+++ b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
@@ -30,8 +30,12 @@ public class ProjectSchemaDefinitions extends SchemaDefinitions<ProjectData> {
ProjectField.NAME_PART,
ProjectField.ANCESTOR_NAME);
+ @Deprecated
static final Schema<ProjectData> V2 = schema(V1, ProjectField.STATE, ProjectField.REF_STATE);
+ // Bump Lucene version requires reindexing
+ static final Schema<ProjectData> V3 = schema(V2);
+
public static final ProjectSchemaDefinitions INSTANCE = new ProjectSchemaDefinitions();
private ProjectSchemaDefinitions() {
diff --git a/java/com/google/gerrit/lucene/AbstractLuceneIndex.java b/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
index dc293cd791..40acf80744 100644
--- a/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
+++ b/java/com/google/gerrit/lucene/AbstractLuceneIndex.java
@@ -64,15 +64,14 @@ import java.util.function.Function;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Field.Store;
-import org.apache.lucene.document.IntField;
-import org.apache.lucene.document.LongField;
+import org.apache.lucene.document.LegacyIntField;
+import org.apache.lucene.document.LegacyLongField;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TrackingIndexWriter;
import org.apache.lucene.search.ControlledRealTimeReopenThread;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@@ -86,6 +85,7 @@ import org.apache.lucene.store.AlreadyClosedException;
import org.apache.lucene.store.Directory;
/** Basic Lucene index implementation. */
+@SuppressWarnings("deprecation")
public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -98,7 +98,7 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
private final Directory dir;
private final String name;
private final ListeningExecutorService writerThread;
- private final TrackingIndexWriter writer;
+ private final IndexWriter writer;
private final ReferenceManager<IndexSearcher> searcherManager;
private final ControlledRealTimeReopenThread<IndexSearcher> reopenThread;
private final Set<NrtFuture> notDoneNrtFutures;
@@ -118,17 +118,16 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
this.dir = dir;
this.name = name;
String index = Joiner.on('_').skipNulls().join(name, subIndex);
- IndexWriter delegateWriter;
long commitPeriod = writerConfig.getCommitWithinMs();
if (commitPeriod < 0) {
- delegateWriter = new AutoCommitWriter(dir, writerConfig.getLuceneConfig());
+ writer = new AutoCommitWriter(dir, writerConfig.getLuceneConfig());
} else if (commitPeriod == 0) {
- delegateWriter = new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), true);
+ writer = new AutoCommitWriter(dir, writerConfig.getLuceneConfig(), true);
} else {
final AutoCommitWriter autoCommitWriter =
new AutoCommitWriter(dir, writerConfig.getLuceneConfig());
- delegateWriter = autoCommitWriter;
+ writer = autoCommitWriter;
autoCommitExecutor =
new LoggingContextAwareScheduledExecutorService(
@@ -165,8 +164,7 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
commitPeriod,
MILLISECONDS);
}
- writer = new TrackingIndexWriter(delegateWriter);
- searcherManager = new WrappableSearcherManager(writer.getIndexWriter(), true, searcherFactory);
+ searcherManager = new WrappableSearcherManager(writer, true, searcherFactory);
notDoneNrtFutures = Sets.newConcurrentHashSet();
@@ -251,7 +249,7 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
}
try {
- writer.getIndexWriter().close();
+ writer.close();
} catch (AlreadyClosedException e) {
// Ignore.
} catch (IOException e) {
@@ -294,7 +292,7 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
writer.deleteAll();
}
- public TrackingIndexWriter getWriter() {
+ public IndexWriter getWriter() {
return writer;
}
@@ -325,15 +323,15 @@ public abstract class AbstractLuceneIndex<K, V> implements Index<K, V> {
if (type == FieldType.INTEGER || type == FieldType.INTEGER_RANGE) {
for (Object value : values.getValues()) {
- doc.add(new IntField(name, (Integer) value, store));
+ doc.add(new LegacyIntField(name, (Integer) value, store));
}
} else if (type == FieldType.LONG) {
for (Object value : values.getValues()) {
- doc.add(new LongField(name, (Long) value, store));
+ doc.add(new LegacyLongField(name, (Long) value, store));
}
} else if (type == FieldType.TIMESTAMP) {
for (Object value : values.getValues()) {
- doc.add(new LongField(name, ((Timestamp) value).getTime(), store));
+ doc.add(new LegacyLongField(name, ((Timestamp) value).getTime(), store));
}
} else if (type == FieldType.EXACT || type == FieldType.PREFIX) {
for (Object value : values.getValues()) {
diff --git a/java/com/google/gerrit/lucene/AutoCommitWriter.java b/java/com/google/gerrit/lucene/AutoCommitWriter.java
index 7a418aa8ca..2cc7563130 100644
--- a/java/com/google/gerrit/lucene/AutoCommitWriter.java
+++ b/java/com/google/gerrit/lucene/AutoCommitWriter.java
@@ -47,58 +47,64 @@ public class AutoCommitWriter extends IndexWriter {
}
@Override
- public void addDocument(Iterable<? extends IndexableField> doc) throws IOException {
- super.addDocument(doc);
+ public long addDocument(Iterable<? extends IndexableField> doc) throws IOException {
+ long ret = super.addDocument(doc);
autoFlush();
+ return ret;
}
@Override
- public void addDocuments(Iterable<? extends Iterable<? extends IndexableField>> docs)
+ public long addDocuments(Iterable<? extends Iterable<? extends IndexableField>> docs)
throws IOException {
- super.addDocuments(docs);
+ long ret = super.addDocuments(docs);
autoFlush();
+ return ret;
}
@Override
- public void updateDocuments(
+ public long updateDocuments(
Term delTerm, Iterable<? extends Iterable<? extends IndexableField>> docs)
throws IOException {
- super.updateDocuments(delTerm, docs);
+ long ret = super.updateDocuments(delTerm, docs);
autoFlush();
+ return ret;
}
@Override
- public void deleteDocuments(Term... term) throws IOException {
- super.deleteDocuments(term);
+ public long deleteDocuments(Term... term) throws IOException {
+ long ret = super.deleteDocuments(term);
autoFlush();
+ return ret;
}
@Override
- public synchronized boolean tryDeleteDocument(IndexReader readerIn, int docID)
- throws IOException {
- boolean ret = super.tryDeleteDocument(readerIn, docID);
- if (ret) {
+ public synchronized long tryDeleteDocument(IndexReader readerIn, int docID) throws IOException {
+ long ret = super.tryDeleteDocument(readerIn, docID);
+ if (ret != -1) {
autoFlush();
}
return ret;
}
@Override
- public void deleteDocuments(Query... queries) throws IOException {
- super.deleteDocuments(queries);
+ public long deleteDocuments(Query... queries) throws IOException {
+ long ret = super.deleteDocuments(queries);
autoFlush();
+ return ret;
}
@Override
- public void updateDocument(Term term, Iterable<? extends IndexableField> doc) throws IOException {
- super.updateDocument(term, doc);
+ public long updateDocument(Term term, Iterable<? extends IndexableField> doc) throws IOException {
+ long ret = super.updateDocument(term, doc);
autoFlush();
+ return ret;
}
@Override
- public void deleteAll() throws IOException {
- super.deleteAll();
+ public long deleteAll() throws IOException {
+ long ret = super.deleteAll();
autoFlush();
+ return ret;
}
void manualFlush() throws IOException {
diff --git a/java/com/google/gerrit/lucene/GerritIndexWriterConfig.java b/java/com/google/gerrit/lucene/GerritIndexWriterConfig.java
index ada3220d49..75e03e32b5 100644
--- a/java/com/google/gerrit/lucene/GerritIndexWriterConfig.java
+++ b/java/com/google/gerrit/lucene/GerritIndexWriterConfig.java
@@ -19,8 +19,8 @@ import static java.util.concurrent.TimeUnit.MINUTES;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.server.config.ConfigUtil;
+import org.apache.lucene.analysis.CharArraySet;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.analysis.util.CharArraySet;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.eclipse.jgit.lib.Config;
diff --git a/java/com/google/gerrit/lucene/QueryBuilder.java b/java/com/google/gerrit/lucene/QueryBuilder.java
index 6aab7c74b7..ce5ba9859a 100644
--- a/java/com/google/gerrit/lucene/QueryBuilder.java
+++ b/java/com/google/gerrit/lucene/QueryBuilder.java
@@ -38,19 +38,20 @@ import java.util.List;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.LegacyNumericRangeQuery;
import org.apache.lucene.search.MatchAllDocsQuery;
-import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RegexpQuery;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.BytesRefBuilder;
-import org.apache.lucene.util.NumericUtils;
+import org.apache.lucene.util.LegacyNumericUtils;
+@SuppressWarnings("deprecation")
public class QueryBuilder<V> {
static Term intTerm(String name, int value) {
BytesRefBuilder builder = new BytesRefBuilder();
- NumericUtils.intToPrefixCoded(value, 0, builder);
+ LegacyNumericUtils.intToPrefixCoded(value, 0, builder);
return new Term(name, builder.get());
}
@@ -180,7 +181,8 @@ public class QueryBuilder<V> {
// Just fall back to a standard integer query.
return new TermQuery(intTerm(p.getField().getName(), minimum));
}
- return NumericRangeQuery.newIntRange(r.getField().getName(), minimum, maximum, true, true);
+ return LegacyNumericRangeQuery.newIntRange(
+ r.getField().getName(), minimum, maximum, true, true);
}
throw new QueryParseException("not an integer range: " + p);
}
@@ -188,7 +190,7 @@ public class QueryBuilder<V> {
private Query timestampQuery(IndexPredicate<V> p) throws QueryParseException {
if (p instanceof TimestampRangePredicate) {
TimestampRangePredicate<V> r = (TimestampRangePredicate<V>) p;
- return NumericRangeQuery.newLongRange(
+ return LegacyNumericRangeQuery.newLongRange(
r.getField().getName(),
r.getMinTimestamp().getTime(),
r.getMaxTimestamp().getTime(),
@@ -200,7 +202,7 @@ public class QueryBuilder<V> {
private Query notTimestamp(TimestampRangePredicate<V> r) throws QueryParseException {
if (r.getMinTimestamp().getTime() == 0) {
- return NumericRangeQuery.newLongRange(
+ return LegacyNumericRangeQuery.newLongRange(
r.getField().getName(), r.getMaxTimestamp().getTime(), null, true, true);
}
throw new QueryParseException("cannot negate: " + r);
diff --git a/java/com/google/gerrit/lucene/WrappableSearcherManager.java b/java/com/google/gerrit/lucene/WrappableSearcherManager.java
index f9ecac38cb..ba8d7dab11 100644
--- a/java/com/google/gerrit/lucene/WrappableSearcherManager.java
+++ b/java/com/google/gerrit/lucene/WrappableSearcherManager.java
@@ -81,11 +81,17 @@ final class WrappableSearcherManager extends ReferenceManager<IndexSearcher> {
WrappableSearcherManager(
IndexWriter writer, boolean applyAllDeletes, SearcherFactory searcherFactory)
throws IOException {
+ // TODO(davido): Make it configurable
+ // If true, new deletes will be written down to index files instead of carried over from writer
+ // to reader directly in heap
+ boolean writeAllDeletes = false;
if (searcherFactory == null) {
searcherFactory = new SearcherFactory();
}
this.searcherFactory = searcherFactory;
- current = getSearcher(searcherFactory, DirectoryReader.open(writer, applyAllDeletes));
+ current =
+ getSearcher(
+ searcherFactory, DirectoryReader.open(writer, applyAllDeletes, writeAllDeletes));
}
/**
diff --git a/java/com/google/gerrit/server/StarredChangesUtil.java b/java/com/google/gerrit/server/StarredChangesUtil.java
index fa6cd6c61a..29974e9941 100644
--- a/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -42,6 +42,8 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndexer;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -376,20 +378,20 @@ public class StarredChangesUtil {
}
public static StarRef readLabels(Repository repo, String refName) throws IOException {
- logger.atFine().log("Read star labels from %s", refName);
-
- Ref ref = repo.exactRef(refName);
- if (ref == null) {
- return StarRef.MISSING;
- }
+ try (TraceTimer traceTimer = TraceContext.newTimer("Read star labels from %s", refName)) {
+ Ref ref = repo.exactRef(refName);
+ if (ref == null) {
+ return StarRef.MISSING;
+ }
- try (ObjectReader reader = repo.newObjectReader()) {
- ObjectLoader obj = reader.open(ref.getObjectId(), Constants.OBJ_BLOB);
- return StarRef.create(
- ref,
- Splitter.on(CharMatcher.whitespace())
- .omitEmptyStrings()
- .split(new String(obj.getCachedBytes(Integer.MAX_VALUE), UTF_8)));
+ try (ObjectReader reader = repo.newObjectReader()) {
+ ObjectLoader obj = reader.open(ref.getObjectId(), Constants.OBJ_BLOB);
+ return StarRef.create(
+ ref,
+ Splitter.on(CharMatcher.whitespace())
+ .omitEmptyStrings()
+ .split(new String(obj.getCachedBytes(Integer.MAX_VALUE), UTF_8)));
+ }
}
}
@@ -450,8 +452,9 @@ public class StarredChangesUtil {
private void updateLabels(
Repository repo, String refName, ObjectId oldObjectId, Collection<String> labels)
throws IOException, OrmException, InvalidLabelsException {
- logger.atFine().log("Update star labels in %s (labels=%s)", refName, labels);
- try (RevWalk rw = new RevWalk(repo)) {
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer("Update star labels in %s (labels=%s)", refName, labels);
+ RevWalk rw = new RevWalk(repo)) {
RefUpdate u = repo.updateRef(refName);
u.setExpectedOldObjectId(oldObjectId);
u.setForceUpdate(true);
@@ -488,31 +491,32 @@ public class StarredChangesUtil {
return;
}
- logger.atFine().log("Delete star labels in %s", refName);
- RefUpdate u = repo.updateRef(refName);
- u.setForceUpdate(true);
- u.setExpectedOldObjectId(oldObjectId);
- u.setRefLogIdent(serverIdent.get());
- u.setRefLogMessage("Unstar change", true);
- RefUpdate.Result result = u.delete();
- switch (result) {
- case FORCED:
- gitRefUpdated.fire(allUsers, u, null);
- return;
- case NEW:
- case NO_CHANGE:
- case FAST_FORWARD:
- case IO_FAILURE:
- case LOCK_FAILURE:
- case NOT_ATTEMPTED:
- case REJECTED:
- case REJECTED_CURRENT_BRANCH:
- case RENAMED:
- case REJECTED_MISSING_OBJECT:
- case REJECTED_OTHER_REASON:
- default:
- throw new OrmException(
- String.format("Delete star ref %s failed: %s", refName, result.name()));
+ try (TraceTimer traceTimer = TraceContext.newTimer("Delete star labels in %s", refName)) {
+ RefUpdate u = repo.updateRef(refName);
+ u.setForceUpdate(true);
+ u.setExpectedOldObjectId(oldObjectId);
+ u.setRefLogIdent(serverIdent.get());
+ u.setRefLogMessage("Unstar change", true);
+ RefUpdate.Result result = u.delete();
+ switch (result) {
+ case FORCED:
+ gitRefUpdated.fire(allUsers, u, null);
+ return;
+ case NEW:
+ case NO_CHANGE:
+ case FAST_FORWARD:
+ case IO_FAILURE:
+ case LOCK_FAILURE:
+ case NOT_ATTEMPTED:
+ case REJECTED:
+ case REJECTED_CURRENT_BRANCH:
+ case RENAMED:
+ case REJECTED_MISSING_OBJECT:
+ case REJECTED_OTHER_REASON:
+ default:
+ throw new OrmException(
+ String.format("Delete star ref %s failed: %s", refName, result.name()));
+ }
}
}
}
diff --git a/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java b/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
index 9bd45330aa..66d65552c8 100644
--- a/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
+++ b/java/com/google/gerrit/server/config/ConfigUpdatedEvent.java
@@ -66,6 +66,10 @@ public class ConfigUpdatedEvent {
return createUpdate(entries, UpdateResult.APPLIED);
}
+ public Update reject(ConfigKey entry) {
+ return reject(Collections.singleton(entry));
+ }
+
public Update reject(Set<ConfigKey> entries) {
return createUpdate(entries, UpdateResult.REJECTED);
}
diff --git a/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java b/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
index c606919d29..66cb3804a4 100644
--- a/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
+++ b/java/com/google/gerrit/server/documentation/QueryDocumentationExecutor.java
@@ -15,12 +15,12 @@
package com.google.gerrit.server.documentation;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
@@ -85,9 +85,9 @@ public class QueryDocumentationExecutor {
// and skipped paging. Maybe add paging later.
TopDocs results = searcher.search(query, Integer.MAX_VALUE);
ScoreDoc[] hits = results.scoreDocs;
- int totalHits = results.totalHits;
+ long totalHits = results.totalHits;
- List<DocResult> out = Lists.newArrayListWithCapacity(totalHits);
+ List<DocResult> out = new ArrayList<>();
for (int i = 0; i < totalHits; i++) {
DocResult result = new DocResult();
Document doc = searcher.doc(hits[i].doc);
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index eb62d547aa..b9ab6fda46 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -110,14 +110,9 @@ public class AsyncReceiveCommits implements PreReceiveHook {
final MultiProgressMonitor progress;
private final Collection<ReceiveCommand> commands;
- private final ReceiveCommits receiveCommits;
private Worker(Collection<ReceiveCommand> commands) {
this.commands = commands;
- receiveCommits =
- factory.create(
- projectState, user, receivePack, allRefsWatcher, extraReviewers, messageSender);
- receiveCommits.init();
progress = new MultiProgressMonitor(new MessageSenderOutputStream(), "Processing changes");
}
@@ -173,7 +168,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
}
}
- private final ReceiveCommits.Factory factory;
+ private final ReceiveCommits receiveCommits;
private final PermissionBackend.ForProject perm;
private final ReceivePack receivePack;
private final ExecutorService executor;
@@ -184,8 +179,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
private final ProjectState projectState;
private final IdentifiedUser user;
private final Repository repo;
- private final MessageSender messageSender;
- private final SetMultimap<ReviewerStateInternal, Account.Id> extraReviewers;
private final AllRefsWatcher allRefsWatcher;
@Inject
@@ -206,7 +199,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
@Assisted @Nullable MessageSender messageSender,
@Assisted SetMultimap<ReviewerStateInternal, Account.Id> extraReviewers)
throws PermissionBackendException {
- this.factory = factory;
this.executor = executor;
this.scopePropagator = scopePropagator;
this.receiveConfig = receiveConfig;
@@ -215,8 +207,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
this.projectState = projectState;
this.user = user;
this.repo = repo;
- this.messageSender = messageSender;
- this.extraReviewers = extraReviewers;
Project.NameKey projectName = projectState.getNameKey();
receivePack = new ReceivePack(repo);
@@ -251,6 +241,11 @@ public class AsyncReceiveCommits implements PreReceiveHook {
advHooks.add(new ReceiveCommitsAdvertiseRefsHook(queryProvider, projectName));
advHooks.add(new HackPushNegotiateHook());
receivePack.setAdvertiseRefsHook(AdvertiseRefsHookChain.newChain(advHooks));
+
+ receiveCommits =
+ factory.create(
+ projectState, user, receivePack, allRefsWatcher, extraReviewers, messageSender);
+ receiveCommits.init();
}
/** Determine if the user can upload commits. */
@@ -275,6 +270,11 @@ public class AsyncReceiveCommits implements PreReceiveHook {
@Override
public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> commands) {
+ if (commands.stream().anyMatch(c -> c.getResult() != Result.NOT_ATTEMPTED)) {
+ // Stop processing when command was already processed by previously invoked
+ // pre-receive hooks
+ return;
+ }
Worker w = new Worker(commands);
try {
w.progress.waitFor(
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index ee751d7541..7566b5593c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -1325,6 +1325,7 @@ class ReceiveCommits {
static class MagicBranchInput {
private static final Splitter COMMAS = Splitter.on(',').omitEmptyStrings();
+ boolean deprecatedTopicSeen;
final ReceiveCommand cmd;
final LabelTypes labelTypes;
final NotesMigration notesMigration;
@@ -1482,6 +1483,7 @@ class ReceiveCommits {
ReceiveCommand cmd,
LabelTypes labelTypes,
NotesMigration notesMigration) {
+ this.deprecatedTopicSeen = false;
this.cmd = cmd;
this.draft = cmd.getRefName().startsWith(MagicBranch.NEW_DRAFT_CHANGE);
this.publish = cmd.getRefName().startsWith(MagicBranch.NEW_PUBLISH_CHANGE);
@@ -1545,8 +1547,7 @@ class ReceiveCommits {
// We accept refs/for/BRANCHNAME/TOPIC. Since we don't know
// for sure where the branch ends and the topic starts, look
- // backward for a split that works. This behavior has not been
- // documented and should probably be deprecated.
+ // backward for a split that works. This behavior is deprecated.
String head = readHEAD(repo);
int split = ref.length();
for (; ; ) {
@@ -1562,6 +1563,7 @@ class ReceiveCommits {
}
if (split < ref.length()) {
topic = Strings.emptyToNull(ref.substring(split + 1));
+ deprecatedTopicSeen = true;
}
return ref.substring(0, split);
}
@@ -1767,6 +1769,13 @@ class ReceiveCommits {
return;
}
+ if (magicBranch.deprecatedTopicSeen) {
+ messages.add(
+ new ValidationMessage(
+ "WARNING: deprecated topic syntax. Use %topic=TOPIC instead", false));
+ logger.atInfo().log("deprecated topic push seen for project %s", project.getName());
+ }
+
if (validateConnected(magicBranch.cmd, magicBranch.dest, tip)) {
this.magicBranch = magicBranch;
}
diff --git a/java/com/google/gerrit/server/index/account/AccountSchemaDefinitions.java b/java/com/google/gerrit/server/index/account/AccountSchemaDefinitions.java
index 3e702f2bfd..6b7fe62322 100644
--- a/java/com/google/gerrit/server/index/account/AccountSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/account/AccountSchemaDefinitions.java
@@ -42,8 +42,12 @@ public class AccountSchemaDefinitions extends SchemaDefinitions<AccountState> {
@Deprecated static final Schema<AccountState> V7 = schema(V6, AccountField.PREFERRED_EMAIL_EXACT);
+ @Deprecated
static final Schema<AccountState> V8 = schema(V7, AccountField.NAME_PART_NO_SECONDARY_EMAIL);
+ // Bump Lucene version requires reindexing
+ static final Schema<AccountState> V9 = schema(V8);
+
public static final String NAME = "accounts";
public static final AccountSchemaDefinitions INSTANCE = new AccountSchemaDefinitions();
diff --git a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
index 5e7e4ddc6f..2000cd176d 100644
--- a/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/change/ChangeSchemaDefinitions.java
@@ -96,7 +96,10 @@ public class ChangeSchemaDefinitions extends SchemaDefinitions<ChangeData> {
// Rename of star label 'mute' to 'reviewed' requires reindexing
@Deprecated static final Schema<ChangeData> V48 = schema(V47);
- static final Schema<ChangeData> V49 = schema(V48);
+ @Deprecated static final Schema<ChangeData> V49 = schema(V48);
+
+ // Bump Lucene version requires reindexing
+ static final Schema<ChangeData> V50 = schema(V49);
public static final String NAME = "changes";
public static final ChangeSchemaDefinitions INSTANCE = new ChangeSchemaDefinitions();
diff --git a/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java b/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
index 912524fe3c..c175434e60 100644
--- a/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
+++ b/java/com/google/gerrit/server/index/group/GroupSchemaDefinitions.java
@@ -37,7 +37,10 @@ public class GroupSchemaDefinitions extends SchemaDefinitions<InternalGroup> {
@Deprecated
static final Schema<InternalGroup> V4 = schema(V3, GroupField.MEMBER, GroupField.SUBGROUP);
- static final Schema<InternalGroup> V5 = schema(V4, GroupField.REF_STATE);
+ @Deprecated static final Schema<InternalGroup> V5 = schema(V4, GroupField.REF_STATE);
+
+ // Bump Lucene version requires reindexing
+ static final Schema<InternalGroup> V6 = schema(V5);
public static final GroupSchemaDefinitions INSTANCE = new GroupSchemaDefinitions();
diff --git a/java/com/google/gerrit/server/logging/TraceContext.java b/java/com/google/gerrit/server/logging/TraceContext.java
index 977baa585d..d68874039b 100644
--- a/java/com/google/gerrit/server/logging/TraceContext.java
+++ b/java/com/google/gerrit/server/logging/TraceContext.java
@@ -192,6 +192,21 @@ public class TraceContext implements AutoCloseable {
return new TraceTimer(format, arg1, arg2);
}
+ /**
+ * Opens a new timer that logs the time for an operation if request tracing is enabled.
+ *
+ * <p>If request tracing is not enabled this is a no-op.
+ *
+ * @param format the message format string
+ * @param arg1 first argument for the message
+ * @param arg2 second argument for the message
+ * @param arg3 third argument for the message
+ * @return the trace timer
+ */
+ public static TraceTimer newTimer(String format, Object arg1, Object arg2, Object arg3) {
+ return new TraceTimer(format, arg1, arg2, arg3);
+ }
+
public static class TraceTimer implements AutoCloseable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -210,6 +225,11 @@ public class TraceContext implements AutoCloseable {
this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg1, arg2, elapsedMs));
}
+ private TraceTimer(
+ String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
+ this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg1, arg2, arg3, elapsedMs));
+ }
+
private TraceTimer(Consumer<Long> logFn) {
this.logFn = logFn;
this.stopwatch = Stopwatch.createStarted();
diff --git a/java/com/google/gerrit/server/permissions/PermissionCollection.java b/java/com/google/gerrit/server/permissions/PermissionCollection.java
index 81e8d24250..b419698415 100644
--- a/java/com/google/gerrit/server/permissions/PermissionCollection.java
+++ b/java/com/google/gerrit/server/permissions/PermissionCollection.java
@@ -26,6 +26,10 @@ import com.google.gerrit.common.data.AccessSection;
import com.google.gerrit.common.data.Permission;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.PermissionRule.Action;
+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.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
@@ -54,10 +58,18 @@ public class PermissionCollection {
@Singleton
public static class Factory {
private final SectionSortCache sorter;
+ // TODO(hiesel): Remove this once we got production data
+ private final Timer0 filterLatency;
@Inject
- Factory(SectionSortCache sorter) {
+ Factory(SectionSortCache sorter, MetricMaker metricMaker) {
this.sorter = sorter;
+ this.filterLatency =
+ metricMaker.newTimer(
+ "permissions/permission_collection/filter_latency",
+ new Description("Latency for access filter computations in PermissionCollection")
+ .setCumulative()
+ .setUnit(Units.NANOSECONDS));
}
/**
@@ -117,41 +129,43 @@ public class PermissionCollection {
*/
PermissionCollection filter(
Iterable<SectionMatcher> matcherList, String ref, CurrentUser user) {
- if (isRE(ref)) {
- ref = RefPattern.shortestExample(ref);
- } else if (ref.endsWith("/*")) {
- ref = ref.substring(0, ref.length() - 1);
- }
+ try (Timer0.Context ignored = filterLatency.start()) {
+ if (isRE(ref)) {
+ ref = RefPattern.shortestExample(ref);
+ } else if (ref.endsWith("/*")) {
+ ref = ref.substring(0, ref.length() - 1);
+ }
- // LinkedHashMap to maintain input ordering.
- Map<AccessSection, Project.NameKey> sectionToProject = new LinkedHashMap<>();
- boolean perUser = filterRefMatchingSections(matcherList, ref, user, sectionToProject);
- List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
+ // LinkedHashMap to maintain input ordering.
+ Map<AccessSection, Project.NameKey> sectionToProject = new LinkedHashMap<>();
+ boolean perUser = filterRefMatchingSections(matcherList, ref, user, sectionToProject);
+ List<AccessSection> sections = Lists.newArrayList(sectionToProject.keySet());
- // Sort by ref pattern specificity. For equally specific patterns, the sections from the
- // project closer to the current one come first.
- sorter.sort(ref, sections);
+ // Sort by ref pattern specificity. For equally specific patterns, the sections from the
+ // project closer to the current one come first.
+ sorter.sort(ref, sections);
- // For block permissions, we want a different order: first, we want to go from parent to
- // child.
- List<Map.Entry<AccessSection, Project.NameKey>> accessDescending =
- Lists.reverse(Lists.newArrayList(sectionToProject.entrySet()));
+ // For block permissions, we want a different order: first, we want to go from parent to
+ // child.
+ List<Map.Entry<AccessSection, Project.NameKey>> accessDescending =
+ Lists.reverse(Lists.newArrayList(sectionToProject.entrySet()));
- Map<Project.NameKey, List<AccessSection>> accessByProject =
- accessDescending
- .stream()
- .collect(
- Collectors.groupingBy(
- Map.Entry::getValue,
- LinkedHashMap::new,
- mapping(Map.Entry::getKey, toList())));
- // Within each project, sort by ref specificity.
- for (List<AccessSection> secs : accessByProject.values()) {
- sorter.sort(ref, secs);
- }
+ Map<Project.NameKey, List<AccessSection>> accessByProject =
+ accessDescending
+ .stream()
+ .collect(
+ Collectors.groupingBy(
+ Map.Entry::getValue,
+ LinkedHashMap::new,
+ mapping(Map.Entry::getKey, toList())));
+ // Within each project, sort by ref specificity.
+ for (List<AccessSection> secs : accessByProject.values()) {
+ sorter.sort(ref, secs);
+ }
- return new PermissionCollection(
- Lists.newArrayList(accessByProject.values()), sections, perUser);
+ return new PermissionCollection(
+ Lists.newArrayList(accessByProject.values()), sections, perUser);
+ }
}
}
diff --git a/java/com/google/gerrit/server/project/CreateProjectArgs.java b/java/com/google/gerrit/server/project/CreateProjectArgs.java
index e4623b227f..a68bd84860 100644
--- a/java/com/google/gerrit/server/project/CreateProjectArgs.java
+++ b/java/com/google/gerrit/server/project/CreateProjectArgs.java
@@ -35,6 +35,8 @@ public class CreateProjectArgs {
public InheritableBoolean newChangeForAllNotInTarget;
public InheritableBoolean changeIdRequired;
public InheritableBoolean rejectEmptyCommit;
+ public InheritableBoolean enableSignedPush;
+ public InheritableBoolean requireSignedPush;
public boolean createEmptyCommit;
public String maxObjectSizeLimit;
@@ -44,6 +46,8 @@ public class CreateProjectArgs {
contentMerge = InheritableBoolean.INHERIT;
changeIdRequired = InheritableBoolean.INHERIT;
newChangeForAllNotInTarget = InheritableBoolean.INHERIT;
+ enableSignedPush = InheritableBoolean.INHERIT;
+ requireSignedPush = InheritableBoolean.INHERIT;
submitType = SubmitType.MERGE_IF_NECESSARY;
}
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index a9b19d9f19..8355625550 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -36,6 +36,11 @@ import com.google.gerrit.extensions.api.projects.ThemeInfo;
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.Description.Units;
+import com.google.gerrit.metrics.Field;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer1;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
import com.google.gerrit.reviewdb.client.Branch;
@@ -92,6 +97,9 @@ public class ProjectState {
private final long globalMaxObjectSizeLimit;
private final boolean inheritProjectMaxObjectSizeLimit;
+ // TODO(hiesel): Remove this once we got production data
+ private final Timer1<String> computationLatency;
+
/** Last system time the configuration's revision was examined. */
private volatile long lastCheckGeneration;
@@ -119,6 +127,7 @@ public class ProjectState {
List<CommentLinkInfo> commentLinks,
CapabilityCollection.Factory limitsFactory,
TransferConfig transferConfig,
+ MetricMaker metricMaker,
@Assisted ProjectConfig config) {
this.sitePaths = sitePaths;
this.projectCache = projectCache;
@@ -136,6 +145,14 @@ public class ProjectState {
this.globalMaxObjectSizeLimit = transferConfig.getMaxObjectSizeLimit();
this.inheritProjectMaxObjectSizeLimit = transferConfig.getInheritProjectMaxObjectSizeLimit();
+ this.computationLatency =
+ metricMaker.newTimer(
+ "permissions/project_state/computation_latency",
+ new Description("Latency for access computations in ProjectState")
+ .setCumulative()
+ .setUnit(Units.NANOSECONDS),
+ Field.ofString("method"));
+
if (isAllProjects && !Permission.canBeOnAllProjects(AccessSection.ALL, Permission.OWNER)) {
localOwners = Collections.emptySet();
} else {
@@ -354,15 +371,20 @@ public class ProjectState {
* cached. Callers should try to cache this result per-request as much as possible.
*/
public List<SectionMatcher> getAllSections() {
- if (isAllProjects) {
- return getLocalAccessSections();
- }
+ try (Timer1.Context ignored = computationLatency.start("getAllSections")) {
+ if (isAllProjects) {
+ return getLocalAccessSections();
+ }
- List<SectionMatcher> all = new ArrayList<>();
- for (ProjectState s : tree()) {
- all.addAll(s.getLocalAccessSections());
+ List<SectionMatcher> all = new ArrayList<>();
+ Iterable<ProjectState> tree = tree();
+ try (Timer1.Context ignored2 = computationLatency.start("getAllSections-parsing-only")) {
+ for (ProjectState s : tree) {
+ all.addAll(s.getLocalAccessSections());
+ }
+ }
+ return all;
}
- return all;
}
/**
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 566786984b..3db72ef43a 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -673,6 +673,21 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
}
@Operator
+ public Predicate<ChangeData> repo(String name) {
+ return project(name);
+ }
+
+ @Operator
+ public Predicate<ChangeData> repos(String name) {
+ return projects(name);
+ }
+
+ @Operator
+ public Predicate<ChangeData> parentrepo(String name) {
+ return parentproject(name);
+ }
+
+ @Operator
public Predicate<ChangeData> branch(String name) {
if (name.startsWith("^")) {
return ref("^" + RefNames.fullName(name.substring(1)));
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index 66e9f90cd3..d6071d5e93 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -157,9 +157,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
info.gerrit = getGerritInfo();
info.noteDbEnabled = toBoolean(isNoteDbEnabled());
info.plugin = getPluginInfo();
- if (Files.exists(sitePaths.site_theme)) {
- info.defaultTheme = "/static/" + SitePaths.THEME_FILENAME;
- }
+ info.defaultTheme = getDefaultTheme();
info.sshd = getSshdInfo();
info.suggest = getSuggestInfo();
@@ -342,6 +340,22 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
return info;
}
+ private static final String DEFAULT_THEME = "/static/" + SitePaths.THEME_FILENAME;
+
+ private String getDefaultTheme() {
+ if (config.getString("theme", null, "enableDefault") == null) {
+ // If not explicitly enabled or disabled, check for the existence of the theme file.
+ return Files.exists(sitePaths.site_theme) ? DEFAULT_THEME : null;
+ }
+ if (config.getBoolean("theme", null, "enableDefault", true)) {
+ // Return non-null theme path without checking for file existence. Even if the file doesn't
+ // exist under the site path, it may be served from a CDN (in which case it's up to the admin
+ // to also pass a proper asset path to the index Soy template).
+ return DEFAULT_THEME;
+ }
+ return null;
+ }
+
private Map<String, String> getUrlAliasesInfo() {
Map<String, String> urlAliases = new HashMap<>();
for (String subsection : config.getSubsections(URL_ALIAS)) {
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index 271848b9de..030402e18d 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -203,6 +203,10 @@ public class CreateProject
MoreObjects.firstNonNull(input.requireChangeId, InheritableBoolean.INHERIT);
args.rejectEmptyCommit =
MoreObjects.firstNonNull(input.rejectEmptyCommit, InheritableBoolean.INHERIT);
+ args.enableSignedPush =
+ MoreObjects.firstNonNull(input.enableSignedPush, InheritableBoolean.INHERIT);
+ args.requireSignedPush =
+ MoreObjects.firstNonNull(input.requireSignedPush, InheritableBoolean.INHERIT);
try {
args.maxObjectSizeLimit = ProjectConfig.validMaxObjectSizeLimit(input.maxObjectSizeLimit);
} catch (ConfigInvalidException e) {
@@ -297,6 +301,8 @@ public class CreateProject
newProject.setBooleanConfig(BooleanProjectConfig.REQUIRE_CHANGE_ID, args.changeIdRequired);
newProject.setBooleanConfig(BooleanProjectConfig.REJECT_EMPTY_COMMIT, args.rejectEmptyCommit);
newProject.setMaxObjectSizeLimit(args.maxObjectSizeLimit);
+ newProject.setBooleanConfig(BooleanProjectConfig.ENABLE_SIGNED_PUSH, args.enableSignedPush);
+ newProject.setBooleanConfig(BooleanProjectConfig.REQUIRE_SIGNED_PUSH, args.requireSignedPush);
if (args.newParent != null) {
newProject.setParentName(args.newParent);
}
diff --git a/java/com/google/gerrit/server/restapi/project/Module.java b/java/com/google/gerrit/server/restapi/project/Module.java
index 04977877dd..8c8ab495f4 100644
--- a/java/com/google/gerrit/server/restapi/project/Module.java
+++ b/java/com/google/gerrit/server/restapi/project/Module.java
@@ -23,7 +23,9 @@ import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
import static com.google.gerrit.server.project.TagResource.TAG_KIND;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.RestApiModule;
+import com.google.gerrit.server.config.GerritConfigListener;
import com.google.gerrit.server.project.RefValidationHelper;
import com.google.gerrit.server.restapi.change.CherryPickCommit;
@@ -41,6 +43,8 @@ public class Module extends RestApiModule {
DynamicMap.mapOf(binder(), COMMIT_KIND);
DynamicMap.mapOf(binder(), TAG_KIND);
+ DynamicSet.bind(binder(), GerritConfigListener.class).to(SetParent.class);
+
create(PROJECT_KIND).to(CreateProject.class);
put(PROJECT_KIND).to(PutProject.class);
get(PROJECT_KIND).to(GetProject.class);
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index 8e1ba6bf34..6abf102d65 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.restapi.project;
import com.google.common.collect.ListMultimap;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -46,6 +47,8 @@ import org.eclipse.jgit.lib.Constants;
@Singleton
public class ProjectsCollection
implements RestCollection<TopLevelResource, ProjectResource>, NeedsParams {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
private final DynamicMap<RestView<ProjectResource>> views;
private final Provider<ListProjects> list;
private final Provider<QueryProjects> queryProjects;
@@ -143,6 +146,8 @@ public class ProjectsCollection
return null;
}
+ logger.atFine().log("Project %s has state %s", nameKey, state.getProject().getState());
+
if (checkAccess) {
// Hidden projects(permitsRead = false) should only be accessible by the project owners.
// WRITE_CONFIG is checked here because it's only allowed to project owners (ACCESS may also
diff --git a/java/com/google/gerrit/server/restapi/project/SetParent.java b/java/com/google/gerrit/server/restapi/project/SetParent.java
index b38619beb4..d4e67b1f7e 100644
--- a/java/com/google/gerrit/server/restapi/project/SetParent.java
+++ b/java/com/google/gerrit/server/restapi/project/SetParent.java
@@ -30,6 +30,9 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ConfigKey;
+import com.google.gerrit.server.config.ConfigUpdatedEvent;
+import com.google.gerrit.server.config.GerritConfigListener;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.permissions.GlobalPermission;
@@ -43,18 +46,21 @@ import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Config;
@Singleton
-public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
+public class SetParent
+ implements RestModifyView<ProjectResource, ParentInput>, GerritConfigListener {
private final ProjectCache cache;
private final PermissionBackend permissionBackend;
private final MetaDataUpdate.Server updateFactory;
private final AllProjectsName allProjects;
private final AllUsersName allUsers;
- private final boolean allowProjectOwnersToChangeParent;
+ private volatile boolean allowProjectOwnersToChangeParent;
@Inject
SetParent(
@@ -164,4 +170,20 @@ public class SetParent implements RestModifyView<ProjectResource, ParentInput> {
}
}
}
+
+ @Override
+ public List<ConfigUpdatedEvent.Update> configUpdated(ConfigUpdatedEvent event) {
+ ConfigKey receiveSetParent = ConfigKey.create("receive", "allowProjectOwnersToChangeParent");
+ if (!event.isValueUpdated(receiveSetParent)) {
+ return Collections.emptyList();
+ }
+ try {
+ boolean enabled =
+ event.getNewConfig().getBoolean("receive", "allowProjectOwnersToChangeParent", false);
+ this.allowProjectOwnersToChangeParent = enabled;
+ return Collections.singletonList(event.accept(receiveSetParent));
+ } catch (IllegalArgumentException iae) {
+ return Collections.singletonList(event.reject(receiveSetParent));
+ }
+ }
}
diff --git a/java/com/google/gerrit/sshd/AliasCommand.java b/java/com/google/gerrit/sshd/AliasCommand.java
index cb61651475..567cf00735 100644
--- a/java/com/google/gerrit/sshd/AliasCommand.java
+++ b/java/com/google/gerrit/sshd/AliasCommand.java
@@ -26,8 +26,8 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.command.Command;
/** Command that executes some other command. */
public class AliasCommand extends BaseCommand {
diff --git a/java/com/google/gerrit/sshd/AliasCommandProvider.java b/java/com/google/gerrit/sshd/AliasCommandProvider.java
index 085b6d6aaa..58e255920a 100644
--- a/java/com/google/gerrit/sshd/AliasCommandProvider.java
+++ b/java/com/google/gerrit/sshd/AliasCommandProvider.java
@@ -17,7 +17,7 @@ package com.google.gerrit.sshd;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.inject.Inject;
import com.google.inject.Provider;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
/** Resolves an alias to another command. */
public class AliasCommandProvider implements Provider<Command> {
diff --git a/java/com/google/gerrit/sshd/BaseCommand.java b/java/com/google/gerrit/sshd/BaseCommand.java
index 942a571325..1d19a8a3ff 100644
--- a/java/com/google/gerrit/sshd/BaseCommand.java
+++ b/java/com/google/gerrit/sshd/BaseCommand.java
@@ -54,9 +54,9 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.sshd.common.SshException;
-import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
+import org.apache.sshd.server.command.Command;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.Option;
diff --git a/java/com/google/gerrit/sshd/CommandFactoryProvider.java b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
index 1fdf7d8203..3fb2ed411b 100644
--- a/java/com/google/gerrit/sshd/CommandFactoryProvider.java
+++ b/java/com/google/gerrit/sshd/CommandFactoryProvider.java
@@ -39,11 +39,11 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.lib.Config;
diff --git a/java/com/google/gerrit/sshd/CommandModule.java b/java/com/google/gerrit/sshd/CommandModule.java
index 93aab0bb45..ac0705679e 100644
--- a/java/com/google/gerrit/sshd/CommandModule.java
+++ b/java/com/google/gerrit/sshd/CommandModule.java
@@ -16,7 +16,7 @@ package com.google.gerrit.sshd;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.inject.binder.LinkedBindingBuilder;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
/** Module to register commands in the SSH daemon. */
public abstract class CommandModule extends LifecycleModule {
diff --git a/java/com/google/gerrit/sshd/CommandProvider.java b/java/com/google/gerrit/sshd/CommandProvider.java
index 61c36cbe53..cf2e84c44b 100644
--- a/java/com/google/gerrit/sshd/CommandProvider.java
+++ b/java/com/google/gerrit/sshd/CommandProvider.java
@@ -15,7 +15,7 @@
package com.google.gerrit.sshd;
import com.google.inject.Provider;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
final class CommandProvider {
diff --git a/java/com/google/gerrit/sshd/Commands.java b/java/com/google/gerrit/sshd/Commands.java
index 43d2c5033a..b6d3401955 100644
--- a/java/com/google/gerrit/sshd/Commands.java
+++ b/java/com/google/gerrit/sshd/Commands.java
@@ -17,7 +17,7 @@ package com.google.gerrit.sshd;
import com.google.auto.value.AutoAnnotation;
import com.google.inject.Key;
import java.lang.annotation.Annotation;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
/** Utilities to support {@link CommandName} construction. */
public class Commands {
diff --git a/java/com/google/gerrit/sshd/DispatchCommand.java b/java/com/google/gerrit/sshd/DispatchCommand.java
index 490dd525af..4c9ca91471 100644
--- a/java/com/google/gerrit/sshd/DispatchCommand.java
+++ b/java/com/google/gerrit/sshd/DispatchCommand.java
@@ -31,8 +31,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.command.Command;
import org.kohsuke.args4j.Argument;
/** Command that dispatches to a subcommand from its command table. */
diff --git a/java/com/google/gerrit/sshd/DispatchCommandProvider.java b/java/com/google/gerrit/sshd/DispatchCommandProvider.java
index c782d2fa4f..7ff7224b9a 100644
--- a/java/com/google/gerrit/sshd/DispatchCommandProvider.java
+++ b/java/com/google/gerrit/sshd/DispatchCommandProvider.java
@@ -24,7 +24,7 @@ import com.google.inject.TypeLiteral;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
/** Creates DispatchCommand using commands registered by {@link CommandModule}. */
public class DispatchCommandProvider implements Provider<DispatchCommand> {
diff --git a/java/com/google/gerrit/sshd/NoShell.java b/java/com/google/gerrit/sshd/NoShell.java
index ba0dcbaaa6..02355547f0 100644
--- a/java/com/google/gerrit/sshd/NoShell.java
+++ b/java/com/google/gerrit/sshd/NoShell.java
@@ -30,10 +30,10 @@ import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.sshd.common.Factory;
-import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.apache.sshd.server.SessionAware;
+import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.util.SystemReader;
diff --git a/java/com/google/gerrit/sshd/PluginCommandModule.java b/java/com/google/gerrit/sshd/PluginCommandModule.java
index b0116e4013..984c8a6aa3 100644
--- a/java/com/google/gerrit/sshd/PluginCommandModule.java
+++ b/java/com/google/gerrit/sshd/PluginCommandModule.java
@@ -18,7 +18,7 @@ import com.google.common.base.Preconditions;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.inject.Inject;
import com.google.inject.binder.LinkedBindingBuilder;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
public abstract class PluginCommandModule extends CommandModule {
private CommandName command;
diff --git a/java/com/google/gerrit/sshd/SingleCommandPluginModule.java b/java/com/google/gerrit/sshd/SingleCommandPluginModule.java
index 079661ad02..5b602f48e9 100644
--- a/java/com/google/gerrit/sshd/SingleCommandPluginModule.java
+++ b/java/com/google/gerrit/sshd/SingleCommandPluginModule.java
@@ -18,7 +18,7 @@ import com.google.common.base.Preconditions;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.inject.Inject;
import com.google.inject.binder.LinkedBindingBuilder;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
/**
* Binds one SSH command to the plugin name itself.
diff --git a/java/com/google/gerrit/sshd/SshAutoRegisterModuleGenerator.java b/java/com/google/gerrit/sshd/SshAutoRegisterModuleGenerator.java
index 0fdde816ce..830dba7755 100644
--- a/java/com/google/gerrit/sshd/SshAutoRegisterModuleGenerator.java
+++ b/java/com/google/gerrit/sshd/SshAutoRegisterModuleGenerator.java
@@ -28,7 +28,7 @@ import com.google.inject.TypeLiteral;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
class SshAutoRegisterModuleGenerator extends AbstractModule implements ModuleGenerator {
private final Map<String, Class<Command>> commands = new HashMap<>();
diff --git a/java/com/google/gerrit/sshd/SshDaemon.java b/java/com/google/gerrit/sshd/SshDaemon.java
index 688c5730ab..ef356f1687 100644
--- a/java/com/google/gerrit/sshd/SshDaemon.java
+++ b/java/com/google/gerrit/sshd/SshDaemon.java
@@ -93,8 +93,6 @@ import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.common.util.net.SshdSocketAddress;
import org.apache.sshd.common.util.security.SecurityUtils;
-import org.apache.sshd.server.Command;
-import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.ServerBuilder;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.auth.UserAuth;
@@ -102,6 +100,8 @@ import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
+import org.apache.sshd.server.command.Command;
+import org.apache.sshd.server.command.CommandFactory;
import org.apache.sshd.server.forward.ForwardingFilter;
import org.apache.sshd.server.global.CancelTcpipForwardHandler;
import org.apache.sshd.server.global.KeepAliveHandler;
diff --git a/java/com/google/gerrit/sshd/SshLog.java b/java/com/google/gerrit/sshd/SshLog.java
index bd8a3ee974..0e34889f08 100644
--- a/java/com/google/gerrit/sshd/SshLog.java
+++ b/java/com/google/gerrit/sshd/SshLog.java
@@ -323,16 +323,20 @@ class SshLog implements LifecycleListener, GerritConfigListener {
if (!event.isValueUpdated(sshdRequestLog)) {
return Collections.emptyList();
}
-
- boolean enabled = event.getNewConfig().getBoolean("sshd", "requestLog", true);
boolean stateUpdated;
- if (enabled) {
- stateUpdated = enableLogging();
- } else {
- stateUpdated = disableLogging();
+ try {
+ boolean enabled = event.getNewConfig().getBoolean("sshd", "requestLog", true);
+
+ if (enabled) {
+ stateUpdated = enableLogging();
+ } else {
+ stateUpdated = disableLogging();
+ }
+ return stateUpdated
+ ? Collections.singletonList(event.accept(sshdRequestLog))
+ : Collections.emptyList();
+ } catch (IllegalArgumentException iae) {
+ return Collections.singletonList(event.reject(sshdRequestLog));
}
- return stateUpdated
- ? Collections.singletonList(event.accept(sshdRequestLog))
- : Collections.emptyList();
}
}
diff --git a/java/com/google/gerrit/sshd/SshModule.java b/java/com/google/gerrit/sshd/SshModule.java
index f047017d6a..acdc9582ed 100644
--- a/java/com/google/gerrit/sshd/SshModule.java
+++ b/java/com/google/gerrit/sshd/SshModule.java
@@ -45,9 +45,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
-import org.apache.sshd.server.CommandFactory;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.server.command.CommandFactory;
import org.eclipse.jgit.lib.Config;
/** Configures standard dependencies for {@link SshDaemon}. */
diff --git a/java/com/google/gerrit/sshd/SshPluginStarterCallback.java b/java/com/google/gerrit/sshd/SshPluginStarterCallback.java
index e9a095f661..6e8590c888 100644
--- a/java/com/google/gerrit/sshd/SshPluginStarterCallback.java
+++ b/java/com/google/gerrit/sshd/SshPluginStarterCallback.java
@@ -24,7 +24,7 @@ import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Singleton;
-import org.apache.sshd.server.Command;
+import org.apache.sshd.server.command.Command;
@Singleton
class SshPluginStarterCallback implements StartPluginListener, ReloadPluginListener {
diff --git a/java/com/google/gerrit/sshd/SuExec.java b/java/com/google/gerrit/sshd/SuExec.java
index 54371c1119..7053a0d5f4 100644
--- a/java/com/google/gerrit/sshd/SuExec.java
+++ b/java/com/google/gerrit/sshd/SuExec.java
@@ -34,8 +34,8 @@ import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
+import org.apache.sshd.server.command.Command;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
diff --git a/java/com/google/gerrit/sshd/commands/CloseConnection.java b/java/com/google/gerrit/sshd/commands/CloseConnection.java
index a38461d7ca..60a878a62c 100644
--- a/java/com/google/gerrit/sshd/commands/CloseConnection.java
+++ b/java/com/google/gerrit/sshd/commands/CloseConnection.java
@@ -53,7 +53,7 @@ final class CloseConnection extends SshCommand {
required = true,
metaVar = "SESSION_ID",
usage = "List of SSH session IDs to be closed")
- private final List<String> sessionIds = new ArrayList<>();
+ private List<String> sessionIds = new ArrayList<>();
@Option(name = "--wait", usage = "wait for connection to close before exiting")
private boolean wait;
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index b74fc16ed0..8891deef08 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -231,6 +231,15 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
}
@Test
+ @GerritConfig(name = "receive.enableSignedPush", value = "true")
+ @TestProjectInput(
+ enableSignedPush = InheritableBoolean.TRUE,
+ requireSignedPush = InheritableBoolean.TRUE)
+ public void nonSignedPushRejectedWhenSignPushRequired() throws Exception {
+ pushTo("refs/for/master").assertErrorStatus("push cert error");
+ }
+
+ @Test
public void pushInitialCommitForRefsMetaConfigBranch() throws Exception {
// delete refs/meta/config
try (Repository repo = repoManager.openRepository(project);
@@ -405,6 +414,7 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
PushOneCommit.Result r = pushTo("refs/for/master/" + topic);
r.assertOkStatus();
r.assertChange(Change.Status.NEW, topic);
+ r.assertMessage("deprecated topic syntax");
// specify topic as option
r = pushTo("refs/for/master%topic=" + topic);
diff --git a/javatests/com/google/gerrit/server/permissions/RefControlTest.java b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
index 31eee9f74c..a3f9f93923 100644
--- a/javatests/com/google/gerrit/server/permissions/RefControlTest.java
+++ b/javatests/com/google/gerrit/server/permissions/RefControlTest.java
@@ -43,6 +43,7 @@ import com.google.gerrit.common.data.PermissionRange;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.errors.InvalidNameException;
import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
+import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -204,6 +205,7 @@ public class RefControlTest {
@Inject private ThreadLocalRequestContext requestContext;
@Inject private DefaultRefFilter.Factory refFilterFactory;
@Inject private TransferConfig transferConfig;
+ @Inject private MetricMaker metricMaker;
@Before
public void setUp() throws Exception {
@@ -291,7 +293,7 @@ public class RefControlTest {
Cache<SectionSortCache.EntryKey, SectionSortCache.EntryVal> c =
CacheBuilder.newBuilder().build();
- sectionSorter = new PermissionCollection.Factory(new SectionSortCache(c));
+ sectionSorter = new PermissionCollection.Factory(new SectionSortCache(c), metricMaker);
parent = new ProjectConfig(parentKey);
parent.load(newRepository(parentKey));
@@ -972,6 +974,7 @@ public class RefControlTest {
commentLinks,
capabilityCollectionFactory,
transferConfig,
+ metricMaker,
pc));
return repo;
}
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 41f60bbe34..b9973e906c 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -201,7 +201,7 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
protected static final String DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY = "has:draft";
protected static final String DASHBOARD_ASSIGNED_QUERY =
- "assignee:${user} (-is:wip OR " + "owner:self OR assignee:self)";
+ "assignee:${user} (-is:wip OR " + "owner:self OR assignee:self) is:open -is:ignored";
protected static final String DASHBOARD_WORK_IN_PROGRESS_QUERY = "is:open owner:${user} is:wip";
protected static final String DASHBOARD_OUTGOING_QUERY =
"is:open owner:${user} -is:wip -is:ignored";
@@ -841,6 +841,43 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
}
@Test
+ public void byRepo() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("repo:foo");
+ assertQuery("repo:repo");
+ assertQuery("repo:repo1", change1);
+ assertQuery("repo:repo2", change2);
+ }
+
+ @Test
+ public void byParentRepo() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2", "repo1");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("parentrepo:repo1", change2, change1);
+ assertQuery("parentrepo:repo2", change2);
+ }
+
+ @Test
+ public void byRepoPrefix() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("repos:foo");
+ assertQuery("repos:repo1", change1);
+ assertQuery("repos:repo2", change2);
+ assertQuery("repos:repo", change2, change1);
+ }
+
+ @Test
public void byBranchAndRef() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChangeForBranch(repo, "master"));
@@ -2746,6 +2783,14 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
.create(repo);
// Create changes that should not be returned by query.
+ new DashboardChangeState(user.getAccountId()).assignTo(user.getAccountId()).abandon();
+ new DashboardChangeState(user.getAccountId())
+ .assignTo(user.getAccountId())
+ .ignoreBy(user.getAccountId());
+ new DashboardChangeState(user.getAccountId())
+ .assignTo(user.getAccountId())
+ .mergeBy(user.getAccountId());
+
assertDashboardQuery("self", DASHBOARD_ASSIGNED_QUERY, selfOpenWip, otherOpenWip);
// Viewing another user's dashboard.
diff --git a/lib/mina/BUILD b/lib/mina/BUILD
index 8595bb52c1..6ee7e41657 100644
--- a/lib/mina/BUILD
+++ b/lib/mina/BUILD
@@ -4,6 +4,7 @@ java_library(
visibility = ["//visibility:public"],
exports = [
":eddsa",
+ "@sshd-mina//jar",
"@sshd//jar",
],
runtime_deps = [":core"],
diff --git a/lib/polymer_externs/BUILD b/lib/polymer_externs/BUILD
index ae8f9c0ffe..2f1bdbded2 100644
--- a/lib/polymer_externs/BUILD
+++ b/lib/polymer_externs/BUILD
@@ -18,16 +18,9 @@ package(
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
-genrule(
- name = "polymer_closure_renamed",
- srcs = ["@polymer_closure//file"],
- outs = ["polymer_closure_renamed.js"],
- cmd = "cp $< $@",
-)
-
closure_js_library(
name = "polymer_closure",
- srcs = [":polymer_closure_renamed"],
+ srcs = ["@polymer_closure//file"],
data = ["//lib:LICENSE-Apache2.0"],
no_closure_library = True,
)
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
index b18e8cd3f1..af320e2b49 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.html
@@ -20,6 +20,9 @@ limitations under the License.
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../change-list/gr-change-list/gr-change-list.html">
<link rel="import" href="../../core/gr-reporting/gr-reporting.html">
+<link rel="import" href="../../shared/gr-button/gr-button.html">
+<link rel="import" href="../../shared/gr-dialog/gr-dialog.html">
+<link rel="import" href="../../shared/gr-overlay/gr-overlay.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../gr-user-header/gr-user-header.html">
@@ -37,18 +40,43 @@ limitations under the License.
gr-change-list {
width: 100%;
}
- .hide {
- display: none;
- }
gr-user-header {
border-bottom: 1px solid var(--border-color);
}
+ .banner {
+ align-items: center;
+ background-color: var(--comment-background-color);
+ border-bottom: 1px solid var(--border-color);
+ display: flex;
+ justify-content: space-between;
+ padding: .25em var(--default-horizontal-margin);
+ }
+ .banner gr-button {
+ --gr-button: {
+ color: var(--primary-text-color);
+ }
+ }
+ .hide {
+ display: none;
+ }
@media only screen and (max-width: 50em) {
.loading {
padding: 0 var(--default-horizontal-margin);
}
}
</style>
+ <div class$="banner [[_computeBannerClass(_showDraftsBanner)]]">
+ <div>
+ You have draft comments on closed changes.
+ <a href$="[[_computeDraftsLink(_showDraftsBanner)]]" target="_blank">(view all)</a>
+ </div>
+ <div>
+ <gr-button
+ class="delete"
+ link
+ on-tap="_handleOpenDeleteDialog">Delete All</gr-button>
+ </div>
+ </div>
<div class="loading" hidden$="[[!_loading]]">Loading...</div>
<div hidden$="[[_loading]]" hidden>
<gr-user-header
@@ -64,6 +92,21 @@ limitations under the License.
on-toggle-star="_handleToggleStar"
on-toggle-reviewed="_handleToggleReviewed"></gr-change-list>
</div>
+ <gr-overlay id="confirmDeleteOverlay" with-backdrop>
+ <gr-dialog
+ id="confirmDeleteDialog"
+ confirm-label="Delete"
+ on-confirm="_handleConfirmDelete"
+ on-cancel="_closeConfirmDeleteOverlay">
+ <div class="header" slot="header">
+ Delete comments
+ </div>
+ <div class="main" slot="main">
+ Are you sure you want to delete all your draft comments in closed changes? This action
+ cannot be undone.
+ </div>
+ </gr-dialog>
+ </gr-overlay>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-reporting id="reporting"></gr-reporting>
</template>
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
index 72ef0e58ba..8aa7084ba4 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.js
@@ -18,67 +18,6 @@
'use strict';
const PROJECT_PLACEHOLDER_PATTERN = /\$\{project\}/g;
- const USER_PLACEHOLDER_PATTERN = /\$\{user\}/g;
-
- // NOTE: These queries are tested in Java. Any changes made to definitions
- // here require corresponding changes to:
- // javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
- const DEFAULT_SECTIONS = [
- {
- // Changes with unpublished draft comments. This section is omitted when
- // viewing other users, so we don't need to filter anything out.
- name: 'Has draft comments',
- query: 'has:draft',
- selfOnly: true,
- hideIfEmpty: true,
- suffixForDashboard: 'limit:10',
- },
- {
- // Changes that are assigned to the viewed user.
- name: 'Assigned reviews',
- query: 'assignee:${user} (-is:wip OR owner:self OR assignee:self)',
- hideIfEmpty: true,
- },
- {
- // WIP open changes owned by viewing user. This section is omitted when
- // viewing other users, so we don't need to filter anything out.
- name: 'Work in progress',
- query: 'is:open owner:${user} is:wip',
- selfOnly: true,
- hideIfEmpty: true,
- },
- {
- // Non-WIP open changes owned by viewed user. Filter out changes ignored
- // by the viewing user.
- name: 'Outgoing reviews',
- query: 'is:open owner:${user} -is:wip -is:ignored',
- },
- {
- // Non-WIP open changes not owned by the viewed user, that the viewed user
- // is associated with (as either a reviewer or the assignee). Changes
- // ignored by the viewing user are filtered out.
- name: 'Incoming reviews',
- query: 'is:open -owner:${user} -is:wip -is:ignored ' +
- '(reviewer:${user} OR assignee:${user})',
- },
- {
- // Open changes the viewed user is CCed on. Changes ignored by the viewing
- // user are filtered out.
- name: 'CCed on',
- query: 'is:open -is:ignored cc:${user}',
- },
- {
- name: 'Recently closed',
- // Closed changes where viewed user is owner, reviewer, or assignee.
- // Changes ignored by the viewing user are filtered out, and so are WIP
- // changes not owned by the viewing user (the one instance of
- // 'owner:self' is intentional and implements this logic).
- query: 'is:closed -is:ignored (-is:wip OR owner:self) ' +
- '(owner:${user} OR reviewer:${user} OR assignee:${user} ' +
- 'OR cc:${user})',
- suffixForDashboard: '-age:4w limit:10',
- },
- ];
Polymer({
is: 'gr-dashboard-view',
@@ -104,10 +43,6 @@
},
_results: Array,
- _sectionMetadata: {
- type: Array,
- value() { return DEFAULT_SECTIONS; },
- },
/**
* For showing a "loading..." string during ajax requests.
@@ -116,6 +51,11 @@
type: Boolean,
value: true,
},
+
+ _showDraftsBanner: {
+ type: Boolean,
+ value: false,
+ },
},
observers: [
@@ -174,16 +114,6 @@
});
},
- _getUserDashboard(user, sections, title) {
- sections = sections
- .filter(section => (user === 'self' || !section.selfOnly))
- .map(section => Object.assign({}, section, {
- name: section.name,
- query: section.query.replace(USER_PLACEHOLDER_PATTERN, user),
- }));
- return Promise.resolve({title, sections});
- },
-
_computeTitle(user) {
if (!user || user === 'self') {
return 'My Reviews';
@@ -221,13 +151,14 @@
const {project, dashboard, title, user, sections} = this.params;
const dashboardPromise = project ?
this._getProjectDashboard(project, dashboard) :
- this._getUserDashboard(
- user || 'self',
- sections || DEFAULT_SECTIONS,
- title || this._computeTitle(user));
+ Promise.resolve(Gerrit.Nav.getUserDashboard(
+ user,
+ sections,
+ title || this._computeTitle(user)));
return dashboardPromise.then(this._fetchDashboardChanges.bind(this))
.then(() => {
+ this._maybeShowDraftsBanner();
this.$.reporting.dashboardDisplayed();
}).catch(err => {
console.warn(err);
@@ -274,5 +205,48 @@
this.$.restAPI.saveChangeReviewed(e.detail.change._number,
e.detail.reviewed);
},
+
+ /**
+ * Banner is shown if a user is on their own dashboard and they have draft
+ * comments on closed changes.
+ */
+ _maybeShowDraftsBanner() {
+ this._showDraftsBanner = false;
+ if (!(this.params.user === 'self')) { return; }
+
+ const draftSection = this._results
+ .find(section => section.query === 'has:draft');
+ if (!draftSection || !draftSection.results.length) { return; }
+
+ const closedChanges = draftSection.results
+ .filter(change => !this.changeIsOpen(change.status));
+ if (!closedChanges.length) { return; }
+
+ this._showDraftsBanner = true;
+ },
+
+ _computeBannerClass(show) {
+ return show ? '' : 'hide';
+ },
+
+ _handleOpenDeleteDialog() {
+ this.$.confirmDeleteOverlay.open();
+ },
+
+ _handleConfirmDelete() {
+ this.$.confirmDeleteDialog.disabled = true;
+ return this.$.restAPI.deleteDraftComments('-is:open').then(() => {
+ this._closeConfirmDeleteOverlay();
+ this._reload();
+ });
+ },
+
+ _closeConfirmDeleteOverlay() {
+ this.$.confirmDeleteOverlay.close();
+ },
+
+ _computeDraftsLink() {
+ return Gerrit.Nav.getUrlForSearchQuery('has:draft -is:open');
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
index cac262718d..aebd452f5e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.html
@@ -63,6 +63,85 @@ limitations under the License.
sandbox.restore();
});
+ suite('drafts banner functionality', () => {
+ suite('_maybeShowDraftsBanner', () => {
+ test('not dashboard/self', () => {
+ element.params = {user: 'notself'};
+ element._maybeShowDraftsBanner();
+ assert.isFalse(element._showDraftsBanner);
+ });
+
+ test('no drafts at all', () => {
+ element.params = {user: 'self'};
+ element._results = [];
+ element._maybeShowDraftsBanner();
+ assert.isFalse(element._showDraftsBanner);
+ });
+
+ test('no drafts on open changes', () => {
+ element.params = {user: 'self'};
+ element._results = [{query: 'has:draft', results: [{status: '_'}]}];
+ sandbox.stub(element, 'changeIsOpen').returns(true);
+ element._maybeShowDraftsBanner();
+ assert.isFalse(element._showDraftsBanner);
+ });
+
+ test('no drafts on open changes', () => {
+ element.params = {user: 'self'};
+ element._results = [{query: 'has:draft', results: [{status: '_'}]}];
+ sandbox.stub(element, 'changeIsOpen').returns(false);
+ element._maybeShowDraftsBanner();
+ assert.isTrue(element._showDraftsBanner);
+ });
+ });
+
+ test('_showDraftsBanner', () => {
+ element._showDraftsBanner = false;
+ flushAsynchronousOperations();
+ assert.isTrue(isHidden(element.$$('.banner')));
+
+ element._showDraftsBanner = true;
+ flushAsynchronousOperations();
+ assert.isFalse(isHidden(element.$$('.banner')));
+ });
+
+ test('delete tap opens dialog', () => {
+ sandbox.stub(element, '_handleOpenDeleteDialog');
+ element._showDraftsBanner = true;
+ flushAsynchronousOperations();
+
+ MockInteractions.tap(element.$$('.banner .delete'));
+ assert.isTrue(element._handleOpenDeleteDialog.called);
+ });
+
+ test('delete comments flow', async () => {
+ sandbox.spy(element, '_handleConfirmDelete');
+ sandbox.stub(element, '_reload');
+
+ // Set up control over timing of when RPC resolves.
+ let deleteDraftCommentsPromiseResolver;
+ const deleteDraftCommentsPromise = new Promise(resolve => {
+ deleteDraftCommentsPromiseResolver = resolve;
+ });
+ sandbox.stub(element.$.restAPI, 'deleteDraftComments')
+ .returns(deleteDraftCommentsPromise);
+
+ // Open confirmation dialog and tap confirm button.
+ await element.$.confirmDeleteOverlay.open();
+ MockInteractions.tap(element.$.confirmDeleteDialog.$.confirm);
+ flushAsynchronousOperations();
+ assert.isTrue(element.$.restAPI.deleteDraftComments
+ .calledWithExactly('-is:open'));
+ assert.isTrue(element.$.confirmDeleteDialog.disabled);
+ assert.equal(element._reload.callCount, 0);
+
+ // Verify state after RPC resolves.
+ deleteDraftCommentsPromiseResolver([]);
+ await deleteDraftCommentsPromise;
+ assert.equal(element._reload.callCount, 1);
+ });
+ });
+
test('_computeTitle', () => {
assert.equal(element._computeTitle('self'), 'My Reviews');
assert.equal(element._computeTitle('not self'), 'Dashboard for not self');
@@ -189,59 +268,6 @@ limitations under the License.
});
});
- suite('_getUserDashboard', () => {
- const sections = [
- {name: 'section 1', query: 'query 1'},
- {name: 'section 2', query: 'query 2 for ${user}'},
- {name: 'section 3', query: 'self only query', selfOnly: true},
- {name: 'section 4', query: 'query 4', suffixForDashboard: 'suffix'},
- ];
-
- test('dashboard for self', () => {
- return element._getUserDashboard('self', sections, 'title')
- .then(dashboard => {
- assert.deepEqual(
- dashboard,
- {
- title: 'title',
- sections: [
- {name: 'section 1', query: 'query 1'},
- {name: 'section 2', query: 'query 2 for self'},
- {
- name: 'section 3',
- query: 'self only query',
- selfOnly: true,
- }, {
- name: 'section 4',
- query: 'query 4',
- suffixForDashboard: 'suffix',
- },
- ],
- });
- });
- });
-
- test('dashboard for other user', () => {
- return element._getUserDashboard('user', sections, 'title')
- .then(dashboard => {
- assert.deepEqual(
- dashboard,
- {
- title: 'title',
- sections: [
- {name: 'section 1', query: 'query 1'},
- {name: 'section 2', query: 'query 2 for user'},
- {
- name: 'section 4',
- query: 'query 4',
- suffixForDashboard: 'suffix',
- },
- ],
- });
- });
- });
- });
-
test('hideIfEmpty sections', () => {
const sections = [
{name: 'test1', query: 'test1', hideIfEmpty: true},
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
index 6af94a1c25..60479e8100 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.js
@@ -241,6 +241,10 @@
];
},
},
+ disableEdit: {
+ type: Boolean,
+ value: false,
+ },
_hasKnownChainState: {
type: Boolean,
value: false,
@@ -397,7 +401,7 @@
'_actionsChanged(actions.*, revisionActions.*, _additionalActions.*)',
'_changeChanged(change)',
'_editStatusChanged(editMode, editPatchsetLoaded, ' +
- 'editBasedOnCurrentPatchSet, actions.*, change.*)',
+ 'editBasedOnCurrentPatchSet, disableEdit, actions.*, change.*)',
],
listeners: {
@@ -575,7 +579,15 @@
},
_editStatusChanged(editMode, editPatchsetLoaded,
- editBasedOnCurrentPatchSet) {
+ editBasedOnCurrentPatchSet, disableEdit) {
+ if (disableEdit) {
+ this._deleteAndNotify('publishEdit');
+ this._deleteAndNotify('rebaseEdit');
+ this._deleteAndNotify('deleteEdit');
+ this._deleteAndNotify('stopEdit');
+ this._deleteAndNotify('edit');
+ return;
+ }
if (editPatchsetLoaded) {
// Only show actions that mutate an edit if an actual edit patch set
// is loaded.
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
index 91b39deede..89d4f1f883 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.html
@@ -439,6 +439,20 @@ limitations under the License.
});
suite('change edits', () => {
+ test('disableEdit', () => {
+ element.set('editMode', false);
+ element.set('editPatchsetLoaded', false);
+ element.change = {status: 'NEW'};
+ element.set('disableEdit', true);
+ flushAsynchronousOperations();
+
+ assert.isNotOk(element.$$('gr-button[data-action-key="publishEdit"]'));
+ assert.isNotOk(element.$$('gr-button[data-action-key="rebaseEdit"]'));
+ assert.isNotOk(element.$$('gr-button[data-action-key="deleteEdit"]'));
+ assert.isNotOk(element.$$('gr-button[data-action-key="edit"]'));
+ assert.isNotOk(element.$$('gr-button[data-action-key="stopEdit"]'));
+ });
+
test('shows confirm dialog for delete edit', () => {
element.set('editMode', true);
element.set('editPatchsetLoaded', true);
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
index b056233d96..5b36221b86 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata-it_test.html
@@ -136,43 +136,42 @@ limitations under the License.
suite('label updates', () => {
let plugin;
- let labelChangeStub;
- setup(done => {
+ setup(() => {
Gerrit.install(p => plugin = p, '0.1',
new URL('test/plugin.html?' + Math.random(),
window.location.href).toString());
sandbox.stub(Gerrit, '_arePluginsLoaded').returns(true);
Gerrit._setPluginsPending([]);
element = createElement();
-
- labelChangeStub = sandbox.stub();
- plugin.changeMetadata().onLabelsChanged(labelChangeStub);
- flush(done);
});
test('labels changed callback', done => {
- assert.equal(labelChangeStub.callCount, 1);
- assert.isTrue(labelChangeStub.calledWithExactly(labels));
- assert.equal(labelChangeStub.args[0][0]['CI'].all.length, 2);
- element.set(['change', 'labels'], {
- CI: {
- all: [
- {value: 1, name: 'user 2', _account_id: 1},
- ],
- values: {
- ' 0': 'Don\'t submit as-is',
- '+1': 'No score',
- '+2': 'Looks good to me',
- },
- },
- });
- // Wait for fake rest API response.
- flush(() => {
- assert.equal(labelChangeStub.callCount, 2);
- assert.equal(labelChangeStub.args[1][0]['CI'].all.length, 1);
- done();
+ let callCount = 0;
+ const labelChangeSpy = sandbox.spy(arg => {
+ callCount++;
+ if (callCount === 1) {
+ assert.deepEqual(arg, labels);
+ assert.equal(arg.CI.all.length, 2);
+ element.set(['change', 'labels'], {
+ CI: {
+ all: [
+ {value: 1, name: 'user 2', _account_id: 1},
+ ],
+ values: {
+ ' 0': 'Don\'t submit as-is',
+ '+1': 'No score',
+ '+2': 'Looks good to me',
+ },
+ },
+ });
+ } else if (callCount === 2) {
+ assert.equal(arg.CI.all.length, 1);
+ done();
+ }
});
+
+ plugin.changeMetadata().onLabelsChanged(labelChangeSpy);
});
});
});
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
index 461bfc402a..8885a6f933 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.html
@@ -394,8 +394,10 @@ limitations under the License.
<span class="headerSubject">[[_change.subject]]</span>
</div><!-- end headerTitle -->
<div class="commitActions" hidden$="[[!_loggedIn]]">
- <gr-change-actions id="actions"
+ <gr-change-actions
+ id="actions"
change="[[_change]]"
+ disable-edit="[[disableEdit]]"
has-parent="[[hasParent]]"
actions="[[_change.actions]]"
revision-actions="[[_currentRevisionActions]]"
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
index ebd72ad9da..4d54161419 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.js
@@ -102,6 +102,10 @@
type: Object,
value() { return document.body; },
},
+ disableEdit: {
+ type: Boolean,
+ value: false,
+ },
_commentThreads: Array,
/** @type {?} */
_serverConfig: {
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index 89b354842e..9822860669 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -112,12 +112,14 @@ limitations under the License.
margin: 5px 4px;
text-decoration: none;
}
+ .invisible,
.settingsButton,
gr-account-dropdown {
display: none;
}
:host([loading]) .accountContainer,
- :host([logged-in]) .loginButton {
+ :host([logged-in]) .loginButton,
+ :host([logged-in]) .registerButton {
display: none;
}
:host([logged-in]) .settingsButton,
@@ -135,7 +137,7 @@ limitations under the License.
text-overflow: ellipsis;
white-space: nowrap;
}
- .loginButton {
+ .loginButton, .registerButton {
color: var(--header-text-color);
padding: .5em 1em;
}
@@ -194,6 +196,13 @@ limitations under the License.
class="hideOnMobile"
name="header-browse-source"></gr-endpoint-decorator>
<div class="accountContainer" id="accountContainer">
+ <div class$="[[_computeIsInvisible(_registerURL)]]">
+ <a
+ class="registerButton"
+ href$="[[_registerURL]]">
+ [[_registerText]]
+ </a>
+ </div>
<a class="loginButton" href$="[[_loginURL]]">Sign in</a>
<a
class="settingsButton"
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
index dad7b7c1c4..738d29e21d 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.js
@@ -62,6 +62,13 @@
},
];
+ // Set of authentication methods that can provide custom registration page.
+ const AUTH_TYPES_WITH_REGISTER_URL = new Set([
+ 'LDAP',
+ 'LDAP_BIND',
+ 'CUSTOM_EXTENSION',
+ ]);
+
Polymer({
is: 'gr-main-header',
@@ -102,7 +109,7 @@
_links: {
type: Array,
computed: '_computeLinks(_defaultLinks, _userLinks, _adminLinks, ' +
- '_docBaseUrl)',
+ '_topMenus, _docBaseUrl)',
},
_loginURL: {
type: String,
@@ -112,6 +119,18 @@
type: Array,
value() { return []; },
},
+ _topMenus: {
+ type: Array,
+ value() { return []; },
+ },
+ _registerText: {
+ type: String,
+ value: 'Sign up',
+ },
+ _registerURL: {
+ type: String,
+ value: null,
+ },
},
behaviors: [
@@ -159,7 +178,7 @@
return '//' + window.location.host + this.getBaseUrl() + path;
},
- _computeLinks(defaultLinks, userLinks, adminLinks, docBaseUrl) {
+ _computeLinks(defaultLinks, userLinks, adminLinks, topMenus, docBaseUrl) {
const links = defaultLinks.slice();
if (userLinks && userLinks.length > 0) {
links.push({
@@ -179,6 +198,12 @@
title: 'Browse',
links: adminLinks,
});
+ for (const m of topMenus) {
+ links.push({
+ title: m.name,
+ links: m.items.map(this._fixCustomMenuItem),
+ });
+ }
return links;
},
@@ -203,6 +228,7 @@
this.loading = true;
const promises = [
this.$.restAPI.getAccount(),
+ this.$.restAPI.getTopMenus(),
Gerrit.awaitPluginsLoaded(),
];
@@ -211,6 +237,7 @@
this._account = account;
this.loggedIn = !!account;
this.loading = false;
+ this._topMenus = result[1];
return this.getAdminLinks(account,
this.$.restAPI.getAccountCapabilities.bind(this.$.restAPI),
@@ -223,7 +250,10 @@
_loadConfig() {
this.$.restAPI.getConfig()
- .then(config => this.getDocsBaseUrl(config, this.$.restAPI))
+ .then(config => {
+ this._retrieveRegisterURL(config);
+ return this.getDocsBaseUrl(config, this.$.restAPI);
+ })
.then(docBaseUrl => { this._docBaseUrl = docBaseUrl; });
},
@@ -232,11 +262,24 @@
this.$.restAPI.getPreferences().then(prefs => {
this._userLinks =
- prefs.my.map(this._fixMyMenuItem).filter(this._isSupportedLink);
+ prefs.my.map(this._fixCustomMenuItem).filter(this._isSupportedLink);
});
},
- _fixMyMenuItem(linkObj) {
+ _retrieveRegisterURL(config) {
+ if (AUTH_TYPES_WITH_REGISTER_URL.has(config.auth.auth_type)) {
+ this._registerURL = config.auth.register_url;
+ if (config.auth.register_text) {
+ this._registerText = config.auth.register_text;
+ }
+ }
+ },
+
+ _computeIsInvisible(registerURL) {
+ return registerURL ? '' : 'invisible';
+ },
+
+ _fixCustomMenuItem(linkObj) {
// Normalize all urls to PolyGerrit style.
if (linkObj.url.startsWith('#')) {
linkObj.url = linkObj.url.slice(1);
@@ -251,7 +294,7 @@
// so we'll just disable it altogether for now.
delete linkObj.target;
- // Becasue the "my menu" links may be arbitrary URLs, we don't know
+ // Because the user provided links may be arbitrary URLs, we don't know
// whether they correspond to any client routes. Mark all such links as
// external.
linkObj.external = true;
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
index 30e8e1fc79..b6e64ec51a 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_test.html
@@ -63,6 +63,8 @@ limitations under the License.
'none');
assert.notEqual(getComputedStyle(element.$$('.loginButton')).display,
'none');
+ assert.notEqual(getComputedStyle(element.$$('.registerButton')).display,
+ 'none');
assert.equal(getComputedStyle(element.$$('gr-account-dropdown')).display,
'none');
assert.equal(getComputedStyle(element.$$('.settingsButton')).display,
@@ -70,6 +72,8 @@ limitations under the License.
element.loggedIn = true;
assert.equal(getComputedStyle(element.$$('.loginButton')).display,
'none');
+ assert.equal(getComputedStyle(element.$$('.registerButton')).display,
+ 'none');
assert.notEqual(getComputedStyle(element.$$('gr-account-dropdown'))
.display,
'none');
@@ -81,7 +85,7 @@ limitations under the License.
assert.deepEqual([
{url: 'https://awesometown.com/#hashyhash'},
{url: 'url', target: '_blank'},
- ].map(element._fixMyMenuItem), [
+ ].map(element._fixCustomMenuItem), [
{url: 'https://awesometown.com/#hashyhash', external: true},
{url: 'url', external: true},
]);
@@ -98,7 +102,6 @@ limitations under the License.
]);
});
-
test('user links', () => {
const defaultLinks = [{
title: 'Faves',
@@ -117,13 +120,13 @@ limitations under the License.
}];
// When no admin links are passed, it should use the default.
- assert.deepEqual(element._computeLinks(defaultLinks, [], adminLinks),
+ assert.deepEqual(element._computeLinks(defaultLinks, [], adminLinks, []),
defaultLinks.concat({
title: 'Browse',
links: adminLinks,
}));
assert.deepEqual(
- element._computeLinks(defaultLinks, userLinks, adminLinks),
+ element._computeLinks(defaultLinks, userLinks, adminLinks, []),
defaultLinks.concat([
{
title: 'Your',
@@ -160,5 +163,61 @@ limitations under the License.
url: 'base/index.html',
}]);
});
+
+ test('top menus', () => {
+ const adminLinks = [{
+ name: 'Repos',
+ url: '/repos',
+ }];
+ const topMenus = [{
+ name: 'Plugins',
+ items: [{
+ name: 'Manage',
+ target: '_blank',
+ url: 'https://gerrit/plugins/plugin-manager/static/index.html',
+ }],
+ }];
+ assert.deepEqual(element._computeLinks([], [], adminLinks, topMenus), [{
+ title: 'Browse',
+ links: adminLinks,
+ },
+ {
+ title: 'Plugins',
+ links: [{
+ name: 'Manage',
+ external: true,
+ url: 'https://gerrit/plugins/plugin-manager/static/index.html',
+ }],
+ }]);
+ });
+
+ test('register URL', () => {
+ const config = {
+ auth: {
+ auth_type: 'LDAP',
+ register_url: 'https//gerrit.example.com/register',
+ },
+ };
+ element._retrieveRegisterURL(config);
+ assert.equal(element._registerURL, config.auth.register_url);
+ assert.equal(element._registerText, 'Sign up');
+
+ config.auth.register_text = 'Create account';
+ element._retrieveRegisterURL(config);
+ assert.equal(element._registerURL, config.auth.register_url);
+ assert.equal(element._registerText, config.auth.register_text);
+ });
+
+ test('register URL ignored for wrong auth type', () => {
+ const config = {
+ auth: {
+ auth_type: 'OPENID',
+ register_url: 'https//gerrit.example.com/register',
+ },
+ };
+ element._retrieveRegisterURL(config);
+ assert.equal(element._registerURL, null);
+ assert.equal(element._registerText, 'Sign up');
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
index c5e32ccade..05cda9b241 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -92,6 +92,69 @@ limitations under the License.
const EDIT_PATCHNUM = 'edit';
const PARENT_PATCHNUM = 'PARENT';
+ const USER_PLACEHOLDER_PATTERN = /\$\{user\}/g;
+
+ // NOTE: These queries are tested in Java. Any changes made to definitions
+ // here require corresponding changes to:
+ // javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+ const DEFAULT_SECTIONS = [
+ {
+ // Changes with unpublished draft comments. This section is omitted when
+ // viewing other users, so we don't need to filter anything out.
+ name: 'Has draft comments',
+ query: 'has:draft',
+ selfOnly: true,
+ hideIfEmpty: true,
+ suffixForDashboard: 'limit:10',
+ },
+ {
+ // Changes that are assigned to the viewed user.
+ name: 'Assigned reviews',
+ query: 'assignee:${user} (-is:wip OR owner:self OR assignee:self) ' +
+ 'is:open -is:ignored',
+ hideIfEmpty: true,
+ },
+ {
+ // WIP open changes owned by viewing user. This section is omitted when
+ // viewing other users, so we don't need to filter anything out.
+ name: 'Work in progress',
+ query: 'is:open owner:${user} is:wip',
+ selfOnly: true,
+ hideIfEmpty: true,
+ },
+ {
+ // Non-WIP open changes owned by viewed user. Filter out changes ignored
+ // by the viewing user.
+ name: 'Outgoing reviews',
+ query: 'is:open owner:${user} -is:wip -is:ignored',
+ },
+ {
+ // Non-WIP open changes not owned by the viewed user, that the viewed user
+ // is associated with (as either a reviewer or the assignee). Changes
+ // ignored by the viewing user are filtered out.
+ name: 'Incoming reviews',
+ query: 'is:open -owner:${user} -is:wip -is:ignored ' +
+ '(reviewer:${user} OR assignee:${user})',
+ },
+ {
+ // Open changes the viewed user is CCed on. Changes ignored by the viewing
+ // user are filtered out.
+ name: 'CCed on',
+ query: 'is:open -is:ignored cc:${user}',
+ },
+ {
+ name: 'Recently closed',
+ // Closed changes where viewed user is owner, reviewer, or assignee.
+ // Changes ignored by the viewing user are filtered out, and so are WIP
+ // changes not owned by the viewing user (the one instance of
+ // 'owner:self' is intentional and implements this logic).
+ query: 'is:closed -is:ignored (-is:wip OR owner:self) ' +
+ '(owner:${user} OR reviewer:${user} OR assignee:${user} ' +
+ 'OR cc:${user})',
+ suffixForDashboard: '-age:4w limit:10',
+ },
+ ];
+
window.Gerrit.Nav = {
View: {
@@ -645,6 +708,17 @@ limitations under the License.
}
return [].concat(this._generateWeblinks(params));
},
+
+ getUserDashboard(user = 'self', sections = DEFAULT_SECTIONS,
+ title = '') {
+ sections = sections
+ .filter(section => (user === 'self' || !section.selfOnly))
+ .map(section => Object.assign({}, section, {
+ name: section.name,
+ query: section.query.replace(USER_PLACEHOLDER_PATTERN, user),
+ }));
+ return {title, sections};
+ },
};
})(window);
</script>
diff --git a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
index 61d1100360..2f7233812e 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation_test.html
@@ -29,5 +29,56 @@ limitations under the License.
assert.throw(() => Gerrit.Nav.getUrlForChange('123', undefined, 12));
assert.throw(() => Gerrit.Nav.getUrlForDiff('123', 'x.c', undefined, 12));
});
+
+ suite('_getUserDashboard', () => {
+ const sections = [
+ {name: 'section 1', query: 'query 1'},
+ {name: 'section 2', query: 'query 2 for ${user}'},
+ {name: 'section 3', query: 'self only query', selfOnly: true},
+ {name: 'section 4', query: 'query 4', suffixForDashboard: 'suffix'},
+ ];
+
+ test('dashboard for self', () => {
+ const dashboard =
+ Gerrit.Nav.getUserDashboard('self', sections, 'title');
+ assert.deepEqual(
+ dashboard,
+ {
+ title: 'title',
+ sections: [
+ {name: 'section 1', query: 'query 1'},
+ {name: 'section 2', query: 'query 2 for self'},
+ {
+ name: 'section 3',
+ query: 'self only query',
+ selfOnly: true,
+ }, {
+ name: 'section 4',
+ query: 'query 4',
+ suffixForDashboard: 'suffix',
+ },
+ ],
+ });
+ });
+
+ test('dashboard for other user', () => {
+ const dashboard =
+ Gerrit.Nav.getUserDashboard('user', sections, 'title');
+ assert.deepEqual(
+ dashboard,
+ {
+ title: 'title',
+ sections: [
+ {name: 'section 1', query: 'query 1'},
+ {name: 'section 2', query: 'query 2 for user'},
+ {
+ name: 'section 4',
+ query: 'query 4',
+ suffixForDashboard: 'suffix',
+ },
+ ],
+ });
+ });
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
index f527aa34b0..58e3125def 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
@@ -102,7 +102,7 @@ limitations under the License.
class="dropdown-trigger" id="trigger"
down-arrow="[[downArrow]]"
on-tap="_dropdownTriggerTapHandler">
- <content></content>
+ <slot></slot>
</gr-button>
<iron-dropdown id="dropdown"
vertical-align="top"
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
index c97c4c77b4..0b90cdf1b6 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.js
@@ -2640,6 +2640,14 @@
});
},
+ getTopMenus(opt_errFn) {
+ return this._fetchJSON({
+ url: '/config/server/top-menus',
+ errFn: opt_errFn,
+ reportUrlAsIs: true,
+ });
+ },
+
setAssignee(changeNum, assignee) {
return this._getChangeURLAndSend({
changeNum,
@@ -2925,5 +2933,13 @@
reportEndpointAsIs: true,
});
},
+
+ deleteDraftComments(query) {
+ return this._send({
+ method: 'POST',
+ url: '/accounts/self/drafts:delete',
+ body: {query},
+ });
+ },
});
})();
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.html b/polygerrit-ui/app/styles/themes/dark-theme.html
index 8ade9ba34e..6037a88f53 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.html
+++ b/polygerrit-ui/app/styles/themes/dark-theme.html
@@ -5,7 +5,7 @@
--view-background-color: #212121;
--border-color: #555555;
--table-header-background-color: #353637;
- --table-subheader-background-color: rgb(23, 27, 31);
+ --table-subheader-background-color: rgb(19, 20, 22);
--header-background-color: #5487E5;
--header-text-color: var(--primary-text-color);
--deemphasized-text-color: #9a9a9a;
@@ -83,4 +83,4 @@
background-color: var(--view-background-color);
}
</style>
-</dom-module> \ No newline at end of file
+</dom-module>
diff --git a/tools/bzl/junit.bzl b/tools/bzl/junit.bzl
index d711356b40..08d50457f9 100644
--- a/tools/bzl/junit.bzl
+++ b/tools/bzl/junit.bzl
@@ -64,6 +64,14 @@ _GenSuite = rule(
implementation = _impl,
)
+POST_JDK8_OPTS = [
+ # Enforce JDK 8 compatibility on Java 9, see
+ # https://docs.oracle.com/javase/9/intl/internationalization-enhancements-jdk-9.htm#JSINT-GUID-AF5AECA7-07C1-4E7D-BC10-BC7E73DC6C7F
+ "-Djava.locale.providers=COMPAT,CLDR,SPI",
+ "--add-modules java.activation",
+ "--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED",
+]
+
def junit_tests(name, srcs, **kwargs):
s_name = name + "TestSuite"
_GenSuite(
@@ -73,13 +81,8 @@ def junit_tests(name, srcs, **kwargs):
)
jvm_flags = kwargs.get("jvm_flags", [])
jvm_flags = jvm_flags + select({
- "//:java9": [
- # Enforce JDK 8 compatibility on Java 9, see
- # https://docs.oracle.com/javase/9/intl/internationalization-enhancements-jdk-9.htm#JSINT-GUID-AF5AECA7-07C1-4E7D-BC10-BC7E73DC6C7F
- "-Djava.locale.providers=COMPAT,CLDR,SPI",
- "--add-modules java.activation",
- "--add-opens=jdk.management/com.sun.management.internal=ALL-UNNAMED",
- ],
+ "//:java9": POST_JDK8_OPTS,
+ "//:java10": POST_JDK8_OPTS,
"//conditions:default": [],
})
native.java_test(
diff --git a/tools/eclipse/project.py b/tools/eclipse/project.py
index 64d837a2b4..e515a3a27c 100755
--- a/tools/eclipse/project.py
+++ b/tools/eclipse/project.py
@@ -53,21 +53,29 @@ opts.add_option('--name', help='name of the generated project',
opts.add_option('-b', '--batch', action='store_true',
dest='batch', help='Bazel batch option')
opts.add_option('-j', '--java', action='store',
- dest='java', help='Post Java 8 support (9|10|11|...)')
+ dest='java', help='Post Java 8 support (9)')
+opts.add_option('-e', '--edge_java', action='store',
+ dest='edge_java', help='Post Java 9 support (10|11|...)')
args, _ = opts.parse_args()
batch_option = '--batch' if args.batch else None
custom_java = args.java
+edge_java = args.edge_java
def _build_bazel_cmd(*args):
+ build = False
cmd = ['bazel']
if batch_option:
cmd.append('--batch')
for arg in args:
+ if arg == "build":
+ build = True
cmd.append(arg)
- if custom_java:
+ if custom_java and not edge_java:
cmd.append('--host_java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java)
cmd.append('--java_toolchain=@bazel_tools//tools/jdk:toolchain_java%s' % custom_java)
+ if edge_java and build:
+ cmd.append(edge_java)
return cmd