Merge "Remove GWT UI"
diff --git a/.mailmap b/.mailmap
index 4c71059..f2fe6ca 100644
--- a/.mailmap
+++ b/.mailmap
@@ -37,6 +37,7 @@
Joel Dodge <dodgejoel@gmail.com> dodgejoel <dodgejoel@gmail.com>
Johan Björk <jbjoerk@gmail.com> Johan Bjork <phb@spotify.com>
JT Olds <hello@jtolds.com> <jtolds@gmail.com>
+Kasper Nilsson <kaspern@google.com> <kaspern@google.com>
Lei Sun <lei.sun01@sap.com> LeiSun <lei.sun01@sap.com>
Lincoln Oliveira Campos Do Nascimento <lincoln.oliveiracamposdonascimento@sonyericsson.com> lincoln <lincoln.oliveiracamposdonascimento@sonyericsson.com>
Luca Milanesio <luca.milanesio@gmail.com> <luca@gitent-scm.com>
diff --git a/Documentation/cmd-plugin-install.txt b/Documentation/cmd-plugin-install.txt
index 5443613..ef68b40 100644
--- a/Documentation/cmd-plugin-install.txt
+++ b/Documentation/cmd-plugin-install.txt
@@ -46,29 +46,25 @@
Install a plugin from an absolute file path on the server's host:
----
- ssh -p 29418 localhost gerrit plugin install -n name.jar \
- $(pwd)/my-plugin.jar
+ssh -p 29418 localhost gerrit plugin install -n name.jar $(pwd)/my-plugin.jar
----
Install a WebUI plugin from an absolute file path on the server's host:
----
- ssh -p 29418 localhost gerrit plugin install -n name.js \
- $(pwd)/my-webui-plugin.js
+ssh -p 29418 localhost gerrit plugin install -n name.js $(pwd)/my-webui-plugin.js
----
Install a plugin from an HTTP site:
----
- ssh -p 29418 localhost gerrit plugin install -n name.jar \
- http://build-server/output/our-plugin
+ssh -p 29418 localhost gerrit plugin install -n name.jar http://build-server/output/our-plugin
----
Install a plugin from piped input:
----
- ssh -p 29418 localhost gerrit plugin install -n name.jar \
- - <target/name-0.1.jar
+ssh -p 29418 localhost gerrit plugin install -n name.jar - <target/name-0.1.jar
----
GERRIT
diff --git a/Documentation/cmd-plugin-reload.txt b/Documentation/cmd-plugin-reload.txt
index ad1e5e7..5cfb6cc 100644
--- a/Documentation/cmd-plugin-reload.txt
+++ b/Documentation/cmd-plugin-reload.txt
@@ -36,7 +36,7 @@
Reload a plugin:
----
- ssh -p 29418 localhost gerrit plugin reload my-plugin
+ssh -p 29418 localhost gerrit plugin reload my-plugin
----
GERRIT
diff --git a/Documentation/cmd-plugin-remove.txt b/Documentation/cmd-plugin-remove.txt
index 805c7b4..f5fe56b 100644
--- a/Documentation/cmd-plugin-remove.txt
+++ b/Documentation/cmd-plugin-remove.txt
@@ -33,7 +33,7 @@
Disable a plugin:
----
- ssh -p 29418 localhost gerrit plugin remove my-plugin
+ssh -p 29418 localhost gerrit plugin remove my-plugin
----
GERRIT
diff --git a/Documentation/cmd-query.txt b/Documentation/cmd-query.txt
index 90e5cdd..79723c5 100644
--- a/Documentation/cmd-query.txt
+++ b/Documentation/cmd-query.txt
@@ -117,18 +117,18 @@
Find the 2 most recent open changes in the tools/gerrit project:
----
- $ ssh -p 29418 review.example.com gerrit query --format=JSON status:open project:tools/gerrit limit:2
- {"project":"tools/gerrit", ...}
- {"project":"tools/gerrit", ...}
- {"type":"stats","rowCount":2,"runningTimeMilliseconds:15}
+$ ssh -p 29418 review.example.com gerrit query --format=JSON status:open project:tools/gerrit limit:2
+{"project":"tools/gerrit", ...}
+{"project":"tools/gerrit", ...}
+{"type":"stats","rowCount":2,"runningTimeMilliseconds:15}
----
Skip number of changes:
----
- $ ssh -p 29418 review.example.com gerrit query --format=JSON --start 42 status:open project:tools/gerrit limit:2
- {"project":"tools/gerrit", ...}
- {"project":"tools/gerrit", ...}
- {"type":"stats","rowCount":1,"runningTimeMilliseconds:15}
+$ ssh -p 29418 review.example.com gerrit query --format=JSON --start 42 status:open project:tools/gerrit limit:2
+{"project":"tools/gerrit", ...}
+{"project":"tools/gerrit", ...}
+{"type":"stats","rowCount":1,"runningTimeMilliseconds:15}
----
diff --git a/Documentation/cmd-receive-pack.txt b/Documentation/cmd-receive-pack.txt
index b62b9a9..9c6d9fa 100644
--- a/Documentation/cmd-receive-pack.txt
+++ b/Documentation/cmd-receive-pack.txt
@@ -1,7 +1,7 @@
= git-receive-pack
== NAME
-git-receive-pack - Receive what is pushed into the repository
+git-receive-pack - Receive what is pushed into the repository.
== SYNOPSIS
[verse]
@@ -43,36 +43,36 @@
Send a review for a change on the master branch to charlie@example.com:
----
- git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com
+git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com
----
Send reviews, but tagging them with the topic name 'bug42':
----
- git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com,topic=bug42
+git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com,topic=bug42
----
Also CC two other parties:
----
- git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
+git push ssh://review.example.com:29418/project HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
----
Configure a push macro to perform the last action:
----
- git config remote.charlie.url ssh://review.example.com:29418/project
- git config remote.charlie.push HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
+git config remote.charlie.url ssh://review.example.com:29418/project
+git config remote.charlie.push HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
----
afterwards `.git/config` contains the following:
----
[remote "charlie"]
- url = ssh://review.example.com:29418/project
- push = HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
+ url = ssh://review.example.com:29418/project
+ push = HEAD:refs/for/master%r=charlie@example.com,cc=alice@example.com,cc=bob@example.com
----
and now sending a new change for review to charlie, CC'ing both
alice and bob is much easier:
----
- git push charlie
+git push charlie
----
== SEE ALSO
diff --git a/Documentation/cmd-reload-config.txt b/Documentation/cmd-reload-config.txt
index 7a25130..6d652f5 100644
--- a/Documentation/cmd-reload-config.txt
+++ b/Documentation/cmd-reload-config.txt
@@ -33,7 +33,7 @@
Reload the gerrit configuration:
----
- ssh -p 29418 localhost gerrit reload-config
+ssh -p 29418 localhost gerrit reload-config
----
GERRIT
diff --git a/Documentation/cmd-rename-group.txt b/Documentation/cmd-rename-group.txt
index a48014c..c946e88 100644
--- a/Documentation/cmd-rename-group.txt
+++ b/Documentation/cmd-rename-group.txt
@@ -32,7 +32,7 @@
Rename the group "MyGroup" to "MyCommitters".
----
- $ ssh -p 29418 user@review.example.com gerrit rename-group MyGroup MyCommitters
+$ ssh -p 29418 user@review.example.com gerrit rename-group MyGroup MyCommitters
----
GERRIT
diff --git a/Documentation/cmd-review.txt b/Documentation/cmd-review.txt
index a407856..5417901 100644
--- a/Documentation/cmd-review.txt
+++ b/Documentation/cmd-review.txt
@@ -1,7 +1,7 @@
= gerrit review
== NAME
-gerrit review - Apply reviews to one or more patch sets
+gerrit review - Apply reviews to one or more patch sets.
== SYNOPSIS
[verse]
@@ -144,35 +144,35 @@
Approve the change with commit c0ff33 as "Verified +1"
----
- $ ssh -p 29418 review.example.com gerrit review --verified +1 c0ff33
+$ ssh -p 29418 review.example.com gerrit review --verified +1 c0ff33
----
Vote on the project specific label "mylabel":
----
- $ ssh -p 29418 review.example.com gerrit review --label mylabel=+1 c0ff33
+$ ssh -p 29418 review.example.com gerrit review --label mylabel=+1 c0ff33
----
Append the message "Build Successful". Notice two levels of quoting is
required, one for the local shell, and another for the argument parser
inside the Gerrit server:
----
- $ ssh -p 29418 review.example.com gerrit review -m '"Build Successful"' c0ff33
+$ ssh -p 29418 review.example.com gerrit review -m '"Build Successful"' c0ff33
----
Mark the unmerged commits both "Verified +1" and "Code-Review +2" and
submit them for merging:
----
- $ ssh -p 29418 review.example.com gerrit review \
- --verified +1 \
- --code-review +2 \
- --submit \
- --project this/project \
- $(git rev-list origin/master..HEAD)
+$ ssh -p 29418 review.example.com gerrit review \
+ --verified +1 \
+ --code-review +2 \
+ --submit \
+ --project this/project \
+ $(git rev-list origin/master..HEAD)
----
Abandon an active change:
----
- $ ssh -p 29418 review.example.com gerrit review --abandon c0ff33
+$ ssh -p 29418 review.example.com gerrit review --abandon c0ff33
----
== SEE ALSO
diff --git a/Documentation/cmd-set-account.txt b/Documentation/cmd-set-account.txt
index 276306e..6808e017 100644
--- a/Documentation/cmd-set-account.txt
+++ b/Documentation/cmd-set-account.txt
@@ -110,7 +110,7 @@
Add an email and SSH key to `watcher`'s account:
----
- $ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit set-account --add-ssh-key - --add-email mail@example.com watcher
+$ cat ~/.ssh/id_watcher.pub | ssh -p 29418 review.example.com gerrit set-account --add-ssh-key - --add-email mail@example.com watcher
----
GERRIT
diff --git a/Documentation/cmd-set-head.txt b/Documentation/cmd-set-head.txt
index f444173..83bdf20 100644
--- a/Documentation/cmd-set-head.txt
+++ b/Documentation/cmd-set-head.txt
@@ -35,7 +35,7 @@
Change HEAD of project `example` to `stable-2.11` branch:
----
- $ ssh -p 29418 review.example.com gerrit set-head example --new-head stable-2.11
+$ ssh -p 29418 review.example.com gerrit set-head example --new-head stable-2.11
----
GERRIT
diff --git a/Documentation/cmd-set-members.txt b/Documentation/cmd-set-members.txt
index 5fb2bb9..141cb33 100644
--- a/Documentation/cmd-set-members.txt
+++ b/Documentation/cmd-set-members.txt
@@ -1,7 +1,7 @@
= gerrit set-members
== NAME
-gerrit set-members - Set group members
+gerrit set-members - Set group members.
== SYNOPSIS
[verse]
@@ -59,16 +59,16 @@
Add alice and bob, but remove eve from the groups my-committers and
my-verifiers.
----
- $ ssh -p 29418 review.example.com gerrit set-members \
- -a alice@example.com -a bob@example.com \
- -r eve@example.com my-committers my-verifiers
+$ ssh -p 29418 review.example.com gerrit set-members \
+ -a alice@example.com -a bob@example.com \
+ -r eve@example.com my-committers my-verifiers
----
Include the group my-friends into the group my-committers, but
exclude the included group my-testers from the group my-committers.
----
- $ ssh -p 29418 review.example.com gerrit set-members \
- -i my-friends -e my-testers my-committers
+$ ssh -p 29418 review.example.com gerrit set-members \
+ -i my-friends -e my-testers my-committers
----
GERRIT
diff --git a/Documentation/cmd-set-project-parent.txt b/Documentation/cmd-set-project-parent.txt
index ec5a5c6..801f15a 100644
--- a/Documentation/cmd-set-project-parent.txt
+++ b/Documentation/cmd-set-project-parent.txt
@@ -51,14 +51,14 @@
Configure `kernel/omap` to inherit permissions from `kernel/common`:
----
- $ ssh -p 29418 review.example.com gerrit set-project-parent --parent kernel/common kernel/omap
+$ ssh -p 29418 review.example.com gerrit set-project-parent --parent kernel/common kernel/omap
----
Reparent all children of `myParent` to `myOtherParent`:
----
- $ ssh -p 29418 review.example.com gerrit set-project-parent \
- --children-of myParent --parent myOtherParent
+$ ssh -p 29418 review.example.com gerrit set-project-parent \
+ --children-of myParent --parent myOtherParent
----
== SEE ALSO
diff --git a/Documentation/cmd-set-project.txt b/Documentation/cmd-set-project.txt
index 7282e28..45b31ff 100644
--- a/Documentation/cmd-set-project.txt
+++ b/Documentation/cmd-set-project.txt
@@ -105,8 +105,8 @@
and use 'merge if necessary' as merge strategy:
----
- $ ssh -p 29418 review.example.com gerrit set-project example --submit-type MERGE_IF_NECESSARY\
- --change-id true --content-merge false --project-state HIDDEN
+$ ssh -p 29418 review.example.com gerrit set-project example --submit-type MERGE_IF_NECESSARY \
+ --change-id true --content-merge false --project-state HIDDEN
----
GERRIT
diff --git a/Documentation/cmd-set-reviewers.txt b/Documentation/cmd-set-reviewers.txt
index eb4335b..5e367c6 100644
--- a/Documentation/cmd-set-reviewers.txt
+++ b/Documentation/cmd-set-reviewers.txt
@@ -1,7 +1,7 @@
= gerrit set-reviewers
== NAME
-gerrit set-reviewers - Add or remove reviewers to a change
+gerrit set-reviewers - Add or remove reviewers to a change.
== SYNOPSIS
[verse]
@@ -56,32 +56,32 @@
Add reviewers alice and bob, but remove eve from change Iac6b2ac2.
----
- $ ssh -p 29418 review.example.com gerrit set-reviewers \
- -a alice@example.com -a bob@example.com \
- -r eve@example.com \
- Iac6b2ac2
+$ ssh -p 29418 review.example.com gerrit set-reviewers \
+ -a alice@example.com -a bob@example.com \
+ -r eve@example.com \
+ Iac6b2ac2
----
Add reviewer elvis to old-style change id 1935 specifying that the change is in project "graceland"
----
- $ ssh -p 29418 review.example.com gerrit set-reviewers \
- --project graceland \
- -a elvis@example.com \
- 1935
+$ ssh -p 29418 review.example.com gerrit set-reviewers \
+ --project graceland \
+ -a elvis@example.com \
+ 1935
----
Add all project owners as reviewers to change Iac6b2ac2.
----
- $ ssh -p 29418 review.example.com gerrit set-reviewers \
- -a "'Project Owners'" \
- Iac6b2ac2
+$ ssh -p 29418 review.example.com gerrit set-reviewers \
+ -a "'Project Owners'" \
+ Iac6b2ac2
----
Add all project owners as reviewers to commit 13dff08acca571b22542ebd2e31acf4572ea0b86.
----
- $ ssh -p 29418 review.example.com gerrit set-reviewers \
- -a "'Project Owners'" \
- 13dff08acca571b22542ebd2e31acf4572ea0b86
+$ ssh -p 29418 review.example.com gerrit set-reviewers \
+ -a "'Project Owners'" \
+ 13dff08acca571b22542ebd2e31acf4572ea0b86
----
GERRIT
diff --git a/Documentation/cmd-show-caches.txt b/Documentation/cmd-show-caches.txt
index 215463b..050118b 100644
--- a/Documentation/cmd-show-caches.txt
+++ b/Documentation/cmd-show-caches.txt
@@ -1,7 +1,7 @@
= gerrit show-caches
== NAME
-gerrit show-caches - Display current cache statistics
+gerrit show-caches - Display current cache statistics.
== SYNOPSIS
[verse]
@@ -51,42 +51,42 @@
== EXAMPLES
----
- $ ssh -p 29418 review.example.com gerrit show-caches
- Gerrit Code Review 2.9 now 11:14:13 CEST
- uptime 6 days 20 hrs
- Name |Entries | AvgGet |Hit Ratio|
- | Mem Disk Space| |Mem Disk|
- --------------------------------+---------------------+---------+---------+
- accounts | 4096 | 3.4ms | 99% |
- adv_bases | | | |
- changes | | 27.1ms | 0% |
- groups | 5646 | 11.8ms | 97% |
- groups_bymember | | | |
- groups_byname | | | |
- groups_bysubgroup | 230 | 2.4ms | 62% |
- groups_byuuid | 5612 | 29.2ms | 99% |
- groups_external | 1 | 1.5s | 98% |
- ldap_group_existence | | | |
- ldap_groups | 650 | 680.5ms | 99% |
- ldap_groups_byinclude | 1024 | | 83% |
- ldap_usernames | 390 | 3.8ms | 81% |
- permission_sort | 16384 | | 99% |
- plugin_resources | | | |
- project_list | 1 | 3.8s | 99% |
- projects | 6477 | 2.9ms | 99% |
- sshkeys | 2048 | 12.5ms | 99% |
- D diff | 1299 62033 132.36m| 22.0ms | 85% 99%|
- D diff_intraline | 12777 218651 128.45m| 171.1ms | 31% 96%|
- D git_tags | 3 6 11.85k| | 0% 100%|
- D web_sessions | 1024 151714 59.10m| | 99% 57%|
+$ ssh -p 29418 review.example.com gerrit show-caches
+Gerrit Code Review 2.9 now 11:14:13 CEST
+ uptime 6 days 20 hrs
+ Name |Entries | AvgGet |Hit Ratio|
+ | Mem Disk Space| |Mem Disk|
+--------------------------------+---------------------+---------+---------+
+ accounts | 4096 | 3.4ms | 99% |
+ adv_bases | | | |
+ changes | | 27.1ms | 0% |
+ groups | 5646 | 11.8ms | 97% |
+ groups_bymember | | | |
+ groups_byname | | | |
+ groups_bysubgroup | 230 | 2.4ms | 62% |
+ groups_byuuid | 5612 | 29.2ms | 99% |
+ groups_external | 1 | 1.5s | 98% |
+ ldap_group_existence | | | |
+ ldap_groups | 650 | 680.5ms | 99% |
+ ldap_groups_byinclude | 1024 | | 83% |
+ ldap_usernames | 390 | 3.8ms | 81% |
+ permission_sort | 16384 | | 99% |
+ plugin_resources | | | |
+ project_list | 1 | 3.8s | 99% |
+ projects | 6477 | 2.9ms | 99% |
+ sshkeys | 2048 | 12.5ms | 99% |
+D diff | 1299 62033 132.36m| 22.0ms | 85% 99%|
+D diff_intraline | 12777 218651 128.45m| 171.1ms | 31% 96%|
+D git_tags | 3 6 11.85k| | 0% 100%|
+D web_sessions | 1024 151714 59.10m| | 99% 57%|
- SSH: 385 users, oldest session started 6 days 20 hrs ago
- Tasks: 10 total = 6 running + 0 ready + 4 sleeping
- Mem: 14.94g total = 3.04g used + 11.89g free + 10.00m buffers
- 28.44g max
- 107 open files
+SSH: 385 users, oldest session started 6 days 20 hrs ago
+Tasks: 10 total = 6 running + 0 ready + 4 sleeping
+Mem: 14.94g total = 3.04g used + 11.89g free + 10.00m buffers
+ 28.44g max
+ 107 open files
- Threads: 4 CPUs available, 371 threads
+Threads: 4 CPUs available, 371 threads
----
== SEE ALSO
diff --git a/Documentation/cmd-show-connections.txt b/Documentation/cmd-show-connections.txt
index 2f70e3c..c5274e1 100644
--- a/Documentation/cmd-show-connections.txt
+++ b/Documentation/cmd-show-connections.txt
@@ -1,7 +1,7 @@
= gerrit show-connections
== NAME
-gerrit show-connections - Display active client SSH connections
+gerrit show-connections - Display active client SSH connections.
== SYNOPSIS
[verse]
@@ -65,20 +65,20 @@
With reverse DNS lookup (default):
----
- $ ssh -p 29418 review.example.com gerrit show-connections
- Session Start Idle User Remote Host
- --------------------------------------------------------------
- 3abf31e6 20:09:02 00:00:00 jdoe jdoe-desktop.example.com
- --
+$ ssh -p 29418 review.example.com gerrit show-connections
+Session Start Idle User Remote Host
+--------------------------------------------------------------
+3abf31e6 20:09:02 00:00:00 jdoe jdoe-desktop.example.com
+--
----
Without reverse DNS lookup:
----
- $ ssh -p 29418 review.example.com gerrit show-connections -n
- Session Start Idle User Remote Host
- --------------------------------------------------------------
- 3abf31e6 20:09:02 00:00:00 a/1001240 10.0.0.1
- --
+$ ssh -p 29418 review.example.com gerrit show-connections -n
+Session Start Idle User Remote Host
+--------------------------------------------------------------
+3abf31e6 20:09:02 00:00:00 a/1001240 10.0.0.1
+--
----
GERRIT
diff --git a/Documentation/cmd-show-queue.txt b/Documentation/cmd-show-queue.txt
index 141f7e2..005ffe0 100644
--- a/Documentation/cmd-show-queue.txt
+++ b/Documentation/cmd-show-queue.txt
@@ -1,7 +1,8 @@
= gerrit show-queue
== NAME
-gerrit show-queue - Display the background work queues, including replication and indexing
+gerrit show-queue - Display the background work queues, including replication
+and indexing.
== SYNOPSIS
[verse]
@@ -75,13 +76,13 @@
and `dst2`:
----
- $ ssh -p 29418 review.example.com gerrit show-queue
- Task State Command
- ------------------------------------------------------------------------------
- 7aae09b2 14:31:15.435 mirror dst1:/home/git/tools/gerrit.git
- 9ad09d27 14:31:25.434 mirror dst2:/var/cache/tools/gerrit.git
- ------------------------------------------------------------------------------
- 2 tasks
+$ ssh -p 29418 review.example.com gerrit show-queue
+Task State Command
+------------------------------------------------------------------------------
+7aae09b2 14:31:15.435 mirror dst1:/home/git/tools/gerrit.git
+9ad09d27 14:31:25.434 mirror dst2:/var/cache/tools/gerrit.git
+------------------------------------------------------------------------------
+2 tasks
----
GERRIT
diff --git a/Documentation/cmd-stream-events.txt b/Documentation/cmd-stream-events.txt
index 37af110..08b661d 100644
--- a/Documentation/cmd-stream-events.txt
+++ b/Documentation/cmd-stream-events.txt
@@ -1,6 +1,6 @@
= gerrit stream-events
== NAME
-gerrit stream-events - Monitor events occurring in real time
+gerrit stream-events - Monitor events occurring in real time.
== SYNOPSIS
[verse]
@@ -37,16 +37,16 @@
== EXAMPLES
----
- $ ssh -p 29418 review.example.com gerrit stream-events
- {"type":"comment-added",change:{"project":"tools/gerrit", ...}, ...}
- {"type":"comment-added",change:{"project":"tools/gerrit", ...}, ...}
+$ ssh -p 29418 review.example.com gerrit stream-events
+{"type":"comment-added",change:{"project":"tools/gerrit", ...}, ...}
+{"type":"comment-added",change:{"project":"tools/gerrit", ...}, ...}
----
Only subscribe to specific event types:
----
- $ ssh -p 29418 review.example.com gerrit stream-events \
- -s patchset-created -s ref-replicated
+$ ssh -p 29418 review.example.com gerrit stream-events \
+ -s patchset-created -s ref-replicated
----
== SCHEMA
diff --git a/Documentation/cmd-suexec.txt b/Documentation/cmd-suexec.txt
index 16338ba..9808edc 100644
--- a/Documentation/cmd-suexec.txt
+++ b/Documentation/cmd-suexec.txt
@@ -1,7 +1,7 @@
= suexec
== NAME
-suexec - Execute a command as any registered user account
+suexec - Execute a command as any registered user account.
== SYNOPSIS
[verse]
@@ -49,13 +49,13 @@
Approve the change with commit c0ff33 as "Verified +1" as user bob@example.com
----
- $ sudo -u gerrit ssh -p 29418 \
- -i site_path/etc/ssh_host_rsa_key \
- "Gerrit Code Review@localhost" \
- suexec \
- --as bob@example.com \
- -- \
- gerrit approve --verified +1 c0ff33
+$ sudo -u gerrit ssh -p 29418 \
+ -i site_path/etc/ssh_host_rsa_key \
+ "Gerrit Code Review@localhost" \
+ suexec \
+ --as bob@example.com \
+ -- \
+ gerrit approve --verified +1 c0ff33
----
GERRIT
diff --git a/Documentation/cmd-test-submit-rule.txt b/Documentation/cmd-test-submit-rule.txt
index b8c4380..33cf2ea 100644
--- a/Documentation/cmd-test-submit-rule.txt
+++ b/Documentation/cmd-test-submit-rule.txt
@@ -29,29 +29,29 @@
Test submit_rule from stdin and return the results as JSON.
----
- cat rules.pl | ssh -p 29418 review.example.com gerrit test-submit rule -s I78f2c6673db24e4e92ed32f604c960dc952437d9
- [
- {
- "status": "NOT_READY",
- "reject": {
- "Any-Label-Name": {}
- }
- }
- ]
+cat rules.pl | ssh -p 29418 review.example.com gerrit test-submit rule -s I78f2c6673db24e4e92ed32f604c960dc952437d9
+[
+ {
+ "status": "NOT_READY",
+ "reject": {
+ "Any-Label-Name": {}
+ }
+ }
+]
----
Test the active submit_rule from the refs/meta/config branch, ignoring filters in the project parents.
----
- $ ssh -p 29418 review.example.com gerrit test-submit rule I78f2c6673db24e4e92ed32f604c960dc952437d9 --no-filters
- [
- {
- "status": "NOT_READY",
- "need": {
- "Code-Review": {}
- "Verified": {}
- }
- }
- ]
+$ ssh -p 29418 review.example.com gerrit test-submit rule I78f2c6673db24e4e92ed32f604c960dc952437d9 --no-filters
+[
+ {
+ "status": "NOT_READY",
+ "need": {
+ "Code-Review": {}
+ "Verified": {}
+ }
+ }
+]
----
== SCRIPTING
diff --git a/Documentation/cmd-test-submit-type.txt b/Documentation/cmd-test-submit-type.txt
index 508684f..48e5e75 100644
--- a/Documentation/cmd-test-submit-type.txt
+++ b/Documentation/cmd-test-submit-type.txt
@@ -29,14 +29,14 @@
Test submit_type from stdin and return the submit type.
----
- cat rules.pl | ssh -p 29418 review.example.com gerrit test-submit type -s I78f2c6673db24e4e92ed32f604c960dc952437d9
- "MERGE_IF_NECESSARY"
+cat rules.pl | ssh -p 29418 review.example.com gerrit test-submit type -s I78f2c6673db24e4e92ed32f604c960dc952437d9
+"MERGE_IF_NECESSARY"
----
Test the active submit_type from the refs/meta/config branch, ignoring filters in the project parents.
----
- $ ssh -p 29418 review.example.com gerrit test-submit type I78f2c6673db24e4e92ed32f604c960dc952437d9 --no-filters
- "MERGE_IF_NECESSARY"
+$ ssh -p 29418 review.example.com gerrit test-submit type I78f2c6673db24e4e92ed32f604c960dc952437d9 --no-filters
+"MERGE_IF_NECESSARY"
----
== SCRIPTING
diff --git a/Documentation/cmd-version.txt b/Documentation/cmd-version.txt
index 85b0491..cdfc779 100644
--- a/Documentation/cmd-version.txt
+++ b/Documentation/cmd-version.txt
@@ -1,7 +1,7 @@
= gerrit version
== NAME
-gerrit version - Show the version of the currently executing Gerrit server
+gerrit version - Show the version of the currently executing Gerrit server.
== SYNOPSIS
[verse]
@@ -34,8 +34,8 @@
== EXAMPLES
----
- $ ssh -p 29418 review.example.com gerrit version
- gerrit version 2.4.2
+$ ssh -p 29418 review.example.com gerrit version
+gerrit version 2.4.2
----
GERRIT
diff --git a/WORKSPACE b/WORKSPACE
index 261e53e..50714f1 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -672,10 +672,10 @@
maven_jar(
name = "blame-cache",
- artifact = "com/google/gitiles:blame-cache:0.2-6",
+ artifact = "com/google/gitiles:blame-cache:0.2-7",
attach_source = False,
repository = GERRIT,
- sha1 = "64827f1bc2cbdbb6515f1d29ce115db94c03bb6a",
+ sha1 = "8170f33b8b1db6f55e41d7069fa050a4d102a62b",
)
# Keep this version of Soy synchronized with the version used in Gitiles.
diff --git a/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java b/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
index 4ed1c0c..8912e31 100644
--- a/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
+++ b/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
@@ -15,7 +15,7 @@
package com.google.gerrit.server.project;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkNotNull;
+import static java.util.Objects.requireNonNull;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.PermissionRule;
@@ -135,7 +135,7 @@
}
private boolean projectMatchesAnyPattern(String projectName, List<String> regexes) {
- checkNotNull(regexes);
+ requireNonNull(regexes);
checkArgument(!regexes.isEmpty());
for (String patternString : regexes) {
Pattern pattern;
diff --git a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
index d1fdf2f..af982cf 100644
--- a/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
+++ b/polygerrit-ui/app/behaviors/keyboard-shortcut-behavior/keyboard-shortcut-behavior.html
@@ -165,6 +165,7 @@
PREV_FILE: 'PREV_FILE',
NEXT_FILE_WITH_COMMENTS: 'NEXT_FILE_WITH_COMMENTS',
PREV_FILE_WITH_COMMENTS: 'PREV_FILE_WITH_COMMENTS',
+ NEXT_UNREVIEWED_FILE: 'NEXT_UNREVIEWED_FILE',
CURSOR_NEXT_FILE: 'CURSOR_NEXT_FILE',
CURSOR_PREV_FILE: 'CURSOR_PREV_FILE',
OPEN_FILE: 'OPEN_FILE',
@@ -255,6 +256,8 @@
'Mark/unmark file as reviewed');
_describe(Shortcut.TOGGLE_DIFF_MODE, ShortcutSection.DIFFS,
'Toggle unified/side-by-side diff');
+ _describe(Shortcut.NEXT_UNREVIEWED_FILE, ShortcutSection.DIFFS,
+ 'Mark file as reviewed and go to next unreviewed file');
_describe(Shortcut.NEXT_FILE, ShortcutSection.NAVIGATION, 'Select next file');
_describe(Shortcut.PREV_FILE, ShortcutSection.NAVIGATION,
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
index 5a463be..4073798 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.js
@@ -128,8 +128,17 @@
});
},
+ _refreshGroupsList() {
+ this.$.restAPI.invalidateGroupsCache(this._filter,
+ this._groupsPerPage, this._offset);
+ return this._getGroups(this._filter, this._groupsPerPage,
+ this._offset);
+ },
+
_handleCreateGroup() {
- this.$.createNewModal.handleCreateGroup();
+ this.$.createNewModal.handleCreateGroup().then(() => {
+ this._refreshGroupsList();
+ });
},
_handleCloseCreate() {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
index 4b82e57..116f084 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.js
@@ -129,8 +129,17 @@
});
},
+ _refreshReposList() {
+ this.$.restAPI.invalidateReposCache(this._filter,
+ this._reposPerPage, this._offset);
+ return this._getRepos(this._filter, this._reposPerPage,
+ this._offset);
+ },
+
_handleCreateRepo() {
- this.$.createNewModal.handleCreateRepo();
+ this.$.createNewModal.handleCreateRepo().then(() => {
+ this._refreshReposList();
+ });
},
_handleCloseCreate() {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
index 6509bb1..bec08a8 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.html
@@ -27,6 +27,7 @@
<link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
+<link rel="import" href="../../shared/gr-icons/gr-icons.html">
<link rel="import" href="../../shared/gr-limited-text/gr-limited-text.html">
<link rel="import" href="../../shared/gr-linked-chip/gr-linked-chip.html">
<link rel="import" href="../../shared/gr-tooltip-content/gr-tooltip-content.html">
@@ -114,6 +115,19 @@
#parentNotCurrentMessage {
display: none;
}
+ .icon {
+ margin: -.25em 0;
+ }
+ .icon.help,
+ .icon.notTrusted {
+ color: #FFA62F;
+ }
+ .icon.invalid {
+ color: var(--vote-text-color-disliked);
+ }
+ .icon.trusted {
+ color: var(--vote-text-color-recommended);
+ }
.parentList.notCurrent.nonMerge #parentNotCurrentMessage {
--arrow-color: #ffa62f;
display: inline-block;
@@ -137,13 +151,40 @@
<span class="title">Owner</span>
<span class="value">
<gr-account-link account="[[change.owner]]"></gr-account-link>
+ <template is="dom-if" if="[[_pushCertificateValidation]]">
+ <gr-tooltip-content
+ has-tooltip
+ title$="[[_pushCertificateValidation.message]]">
+ <iron-icon
+ class$="icon [[_pushCertificateValidation.class]]"
+ icon="[[_pushCertificateValidation.icon]]">
+ </iron-icon>
+ </gr-tooltip-content>
+ </template>
</span>
</section>
- <section class$="[[_computeShowUploaderHide(change)]]">
+ <section class$="[[_computeShowRoleClass(change, _CHANGE_ROLE.UPLOADER)]]">
<span class="title">Uploader</span>
<span class="value">
<gr-account-link
- account="[[_computeShowUploader(change)]]"></gr-account-link>
+ account="[[_getNonOwnerRole(change, _CHANGE_ROLE.UPLOADER)]]"
+ ></gr-account-link>
+ </span>
+ </section>
+ <section class$="[[_computeShowRoleClass(change, _CHANGE_ROLE.AUTHOR)]]">
+ <span class="title">Author</span>
+ <span class="value">
+ <gr-account-link
+ account="[[_getNonOwnerRole(change, _CHANGE_ROLE.AUTHOR)]]"
+ ></gr-account-link>
+ </span>
+ </section>
+ <section class$="[[_computeShowRoleClass(change, _CHANGE_ROLE.COMMITTER)]]">
+ <span class="title">Committer</span>
+ <span class="value">
+ <gr-account-link
+ account="[[_getNonOwnerRole(change, _CHANGE_ROLE.COMMITTER)]]"
+ ></gr-account-link>
</span>
</section>
<section class="assignee">
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
index 8d1546b..d3fc7e0 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.js
@@ -17,6 +17,17 @@
(function() {
'use strict';
+ const Defs = {};
+
+ /**
+ * @typedef {{
+ * message: string,
+ * icon: string,
+ * class: string,
+ * }}
+ */
+ Defs.PushCertificateValidation;
+
const HASHTAG_ADD_MESSAGE = 'Add Hashtag';
const SubmitTypeLabel = {
@@ -30,6 +41,24 @@
const NOT_CURRENT_MESSAGE = 'Not current - rebase possible';
+ /**
+ * @enum {string}
+ */
+ const CertificateStatus = {
+ /**
+ * This certificate status is bad.
+ */
+ BAD: 'BAD',
+ /**
+ * This certificate status is OK.
+ */
+ OK: 'OK',
+ /**
+ * This certificate status is TRUSTED.
+ */
+ TRUSTED: 'TRUSTED',
+ };
+
Polymer({
is: 'gr-change-metadata',
@@ -76,6 +105,13 @@
type: Boolean,
computed: '_computeShowReviewersByState(serverConfig)',
},
+ /**
+ * @type {Defs.PushCertificateValidation}
+ */
+ _pushCertificateValidation: {
+ type: Object,
+ computed: '_computePushCertificateValidation(serverConfig, change)',
+ },
_showRequirements: {
type: Boolean,
computed: '_computeShowRequirements(change)',
@@ -97,6 +133,18 @@
type: Array,
computed: '_computeParents(change)',
},
+
+ /** @type {?} */
+ _CHANGE_ROLE: {
+ type: Object,
+ readOnly: true,
+ value: {
+ OWNER: 'owner',
+ UPLOADER: 'uploader',
+ AUTHOR: 'author',
+ COMMITTER: 'committer',
+ },
+ },
},
behaviors: [
@@ -248,6 +296,59 @@
return hasRequirements || hasLabels || !!change.work_in_progress;
},
+ /**
+ * @return {?Defs.PushCertificateValidation} object representing data for
+ * the push validation.
+ */
+ _computePushCertificateValidation(serverConfig, change) {
+ if (!serverConfig || !serverConfig.receive ||
+ !serverConfig.receive.enable_signed_push) {
+ return null;
+ }
+ const rev = change.revisions[change.current_revision];
+ if (!rev.push_certificate || !rev.push_certificate.key) {
+ return {
+ class: 'help',
+ icon: 'gr-icons:help',
+ message: 'This patch set was created without a push certificate',
+ };
+ }
+
+ const key = rev.push_certificate.key;
+ switch (key.status) {
+ case CertificateStatus.BAD:
+ return {
+ class: 'invalid',
+ icon: 'gr-icons:close',
+ message: this._problems('Push certificate is invalid', key),
+ };
+ case CertificateStatus.OK:
+ return {
+ class: 'notTrusted',
+ icon: 'gr-icons:info',
+ message: this._problems(
+ 'Push certificate is valid, but key is not trusted', key),
+ };
+ case CertificateStatus.TRUSTED:
+ return {
+ class: 'trusted',
+ icon: 'gr-icons:check',
+ message: this._problems(
+ 'Push certificate is valid and key is trusted', key),
+ };
+ default:
+ throw new Error(`unknown certificate status: ${key.status}`);
+ }
+ },
+
+ _problems(msg, key) {
+ if (!key || !key.problems || key.problems.length === 0) {
+ return msg;
+ }
+
+ return [msg + ':'].concat(key.problems).join('\n');
+ },
+
_computeProjectURL(project) {
return Gerrit.Nav.getUrlForProjectChanges(project);
},
@@ -299,24 +400,45 @@
return !!change.work_in_progress;
},
- _computeShowUploaderHide(change) {
- return this._computeShowUploader(change) ? '' : 'hideDisplay';
+ _computeShowRoleClass(change, role) {
+ return this._getNonOwnerRole(change, role) ? '' : 'hideDisplay';
},
- _computeShowUploader(change) {
+ /**
+ * Get the user with the specified role on the change. Returns null if the
+ * user with that role is the same as the owner.
+ * @param {!Object} change
+ * @param {string} role One of the values from _CHANGE_ROLE
+ * @return {Object|null} either an accound or null.
+ */
+ _getNonOwnerRole(change, role) {
if (!change.current_revision ||
!change.revisions[change.current_revision]) {
return null;
}
const rev = change.revisions[change.current_revision];
+ if (!rev) { return null; }
- if (!rev || !rev.uploader ||
- change.owner._account_id === rev.uploader._account_id) {
- return null;
+ if (role === this._CHANGE_ROLE.UPLOADER &&
+ rev.uploader &&
+ change.owner._account_id !== rev.uploader._account_id) {
+ return rev.uploader;
}
- return rev.uploader;
+ if (role === this._CHANGE_ROLE.AUTHOR &&
+ rev.commit && rev.commit.author &&
+ change.owner.email !== rev.commit.author.email) {
+ return rev.commit.author;
+ }
+
+ if (role === this._CHANGE_ROLE.COMMITTER &&
+ rev.commit && rev.commit.committer &&
+ change.owner.email !== rev.commit.committer.email) {
+ return rev.commit.committer;
+ }
+
+ return null;
},
_computeParents(change) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
index af25d91..c5a569e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.html
@@ -185,7 +185,138 @@
assert.equal(element._computeWebLinks(element.commitInfo).length, 1);
});
- test('_computeShowUploader test for uploader', () => {
+ suite('_getNonOwnerRole', () => {
+ let change;
+
+ setup(() => {
+ change = {
+ owner: {
+ email: 'abc@def',
+ _account_id: 1019328,
+ },
+ revisions: {
+ rev1: {
+ _number: 1,
+ uploader: {
+ email: 'ghi@def',
+ _account_id: 1011123,
+ },
+ commit: {
+ author: {email: 'jkl@def'},
+ committer: {email: 'ghi@def'},
+ },
+ },
+ },
+ current_revision: 'rev1',
+ };
+ });
+
+ suite('role=uploader', () => {
+ test('_getNonOwnerRole for uploader', () => {
+ assert.deepEqual(
+ element._getNonOwnerRole(change, element._CHANGE_ROLE.UPLOADER),
+ {email: 'ghi@def', _account_id: 1011123});
+ });
+
+ test('_getNonOwnerRole that it does not return uploader', () => {
+ // Set the uploader email to be the same as the owner.
+ change.revisions.rev1.uploader._account_id = 1019328;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.UPLOADER));
+ });
+
+ test('_getNonOwnerRole null for uploader with no current rev', () => {
+ delete change.current_revision;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.UPLOADER));
+ });
+
+ test('_computeShowRoleClass show uploader', () => {
+ assert.equal(element._computeShowRoleClass(
+ change, element._CHANGE_ROLE.UPLOADER), '');
+ });
+
+ test('_computeShowRoleClass hide uploader', () => {
+ // Set the uploader email to be the same as the owner.
+ change.revisions.rev1.uploader._account_id = 1019328;
+ assert.equal(element._computeShowRoleClass(change,
+ element._CHANGE_ROLE.UPLOADER), 'hideDisplay');
+ });
+ });
+
+ suite('role=committer', () => {
+ test('_getNonOwnerRole for committer', () => {
+ assert.deepEqual(
+ element._getNonOwnerRole(change, element._CHANGE_ROLE.COMMITTER),
+ {email: 'ghi@def'});
+ });
+
+ test('_getNonOwnerRole that it does not return committer', () => {
+ // Set the committer email to be the same as the owner.
+ change.revisions.rev1.commit.committer.email = 'abc@def';
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.COMMITTER));
+ });
+
+ test('_getNonOwnerRole null for committer with no current rev', () => {
+ delete change.current_revision;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.COMMITTER));
+ });
+
+ test('_getNonOwnerRole null for committer with no commit', () => {
+ delete change.revisions.rev1.commit;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.COMMITTER));
+ });
+
+ test('_getNonOwnerRole null for committer with no committer', () => {
+ delete change.revisions.rev1.commit.committer;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.COMMITTER));
+ });
+ });
+
+ suite('role=author', () => {
+ test('_getNonOwnerRole for author', () => {
+ assert.deepEqual(
+ element._getNonOwnerRole(change, element._CHANGE_ROLE.AUTHOR),
+ {email: 'jkl@def'});
+ });
+
+ test('_getNonOwnerRole that it does not return author', () => {
+ // Set the author email to be the same as the owner.
+ change.revisions.rev1.commit.author.email = 'abc@def';
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.AUTHOR));
+ });
+
+ test('_getNonOwnerRole null for author with no current rev', () => {
+ delete change.current_revision;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.AUTHOR));
+ });
+
+ test('_getNonOwnerRole null for author with no commit', () => {
+ delete change.revisions.rev1.commit;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.AUTHOR));
+ });
+
+ test('_getNonOwnerRole null for author with no author', () => {
+ delete change.revisions.rev1.commit.author;
+ assert.isNull(element._getNonOwnerRole(change,
+ element._CHANGE_ROLE.AUTHOR));
+ });
+ });
+ });
+
+ test('Push Certificate Validation test BAD', () => {
+ const serverConfig = {
+ receive: {
+ enable_signed_push: true,
+ },
+ };
const change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
owner: {
@@ -194,8 +325,13 @@
revisions: {
rev1: {
_number: 1,
- uploader: {
- _account_id: 1011123,
+ push_certificate: {
+ key: {
+ status: 'BAD',
+ problems: [
+ 'No public keys found for key ID E5E20E52',
+ ],
+ },
},
},
},
@@ -204,54 +340,21 @@
labels: {},
mergeable: true,
};
- assert.deepEqual(element._computeShowUploader(change),
- {_account_id: 1011123});
+ const result =
+ element._computePushCertificateValidation(serverConfig, change);
+ assert.equal(result.message,
+ 'Push certificate is invalid:\n' +
+ 'No public keys found for key ID E5E20E52');
+ assert.equal(result.icon, 'gr-icons:close');
+ assert.equal(result.class, 'invalid');
});
- test('_computeShowUploader test that it does not return uploader', () => {
- const change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- owner: {
- _account_id: 1011123,
+ test('Push Certificate Validation test TRUSTED', () => {
+ const serverConfig = {
+ receive: {
+ enable_signed_push: true,
},
- revisions: {
- rev1: {
- _number: 1,
- uploader: {
- _account_id: 1011123,
- },
- },
- },
- current_revision: 'rev1',
- status: 'NEW',
- labels: {},
- mergeable: true,
};
- assert.isNotOk(element._computeShowUploader(change));
- });
-
- test('no current_revision makes _computeShowUploader return null', () => {
- const change = {
- change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
- owner: {
- _account_id: 1011123,
- },
- revisions: {
- rev1: {
- _number: 1,
- uploader: {
- _account_id: 1011123,
- },
- },
- },
- status: 'NEW',
- labels: {},
- mergeable: true,
- };
- assert.isNotOk(element._computeShowUploader(change));
- });
-
- test('_computeShowUploaderHide test for string which equals true', () => {
const change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
owner: {
@@ -260,8 +363,10 @@
revisions: {
rev1: {
_number: 1,
- uploader: {
- _account_id: 1011123,
+ push_certificate: {
+ key: {
+ status: 'TRUSTED',
+ },
},
},
},
@@ -270,21 +375,28 @@
labels: {},
mergeable: true,
};
- assert.equal(element._computeShowUploaderHide(change), '');
+ const result =
+ element._computePushCertificateValidation(serverConfig, change);
+ assert.equal(result.message,
+ 'Push certificate is valid and key is trusted');
+ assert.equal(result.icon, 'gr-icons:check');
+ assert.equal(result.class, 'trusted');
});
- test('_computeShowUploaderHide test for hideDisplay', () => {
+ test('Push Certificate Validation is missing test', () => {
+ const serverConfig = {
+ receive: {
+ enable_signed_push: true,
+ },
+ };
const change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
owner: {
- _account_id: 1011123,
+ _account_id: 1019328,
},
revisions: {
rev1: {
_number: 1,
- uploader: {
- _account_id: 1011123,
- },
},
},
current_revision: 'rev1',
@@ -292,8 +404,12 @@
labels: {},
mergeable: true,
};
- assert.equal(
- element._computeShowUploaderHide(change), 'hideDisplay');
+ const result =
+ element._computePushCertificateValidation(serverConfig, change);
+ assert.equal(result.message,
+ 'This patch set was created without a push certificate');
+ assert.equal(result.icon, 'gr-icons:help');
+ assert.equal(result.class, 'help');
});
test('_computeParents', () => {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
index f9745b8..a88142e 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.html
@@ -599,6 +599,7 @@
};
element._change = {
change_id: 'Iad9dc96274af6946f3632be53b106ef80f7ba6ca',
+ owner: {email: 'abc@def'},
revisions: {
rev2: {_number: 2, commit: {parents: []}},
rev1: {_number: 1, commit: {parents: []}},
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index 65d681d..9f9f026 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -43,7 +43,7 @@
};
const ButtonTooltips = {
- SAVE: 'Save reply but do not send',
+ SAVE: 'Save reply but do not send notification',
START_REVIEW: 'Mark as ready for review and send reply',
SEND: 'Send reply',
};
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.js b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
index f4f36b3..8ae30ad 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.js
@@ -324,14 +324,10 @@
if (!weblinks || !weblinks.length) return [];
return weblinks.filter(weblink => !this._isDirectCommit(weblink)).map(
({name, url}) => {
- if (url.startsWith('https:') || url.startsWith('http:')) {
- return {name, url};
- } else {
- return {
- name,
- url: `../../${url}`,
- };
+ if (!url.startsWith('https:') && !url.startsWith('http:')) {
+ url = this.getBaseUrl() + (url.startsWith('/') ? '' : '/') + url;
}
+ return {name, url};
});
},
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
index b9eaa18..584fb35 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.html
@@ -44,6 +44,23 @@
teardown(() => { sandbox.restore(); });
+ test('_getChangeWeblinks', () => {
+ sandbox.stub(element, '_isDirectCommit').returns(false);
+ sandbox.stub(element, 'getBaseUrl').returns('base');
+ const link = {name: 'test', url: 'test/url'};
+ const mapLinksToConfig = weblink => ({options: {weblinks: [weblink]}});
+ assert.deepEqual(element._getChangeWeblinks(mapLinksToConfig(link))[0],
+ {name: 'test', url: 'base/test/url'});
+
+ link.url = '/' + link.url;
+ assert.deepEqual(element._getChangeWeblinks(mapLinksToConfig(link))[0],
+ {name: 'test', url: 'base/test/url'});
+
+ link.url = 'https:/' + link.url;
+ assert.deepEqual(element._getChangeWeblinks(mapLinksToConfig(link))[0],
+ {name: 'test', url: 'https://test/url'});
+ });
+
test('_getHashFromCanonicalPath', () => {
let url = '/foo/bar';
let hash = element._getHashFromCanonicalPath(url);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
index a9242be..d2731a2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-binary.js
@@ -20,9 +20,9 @@
// Prevent redefinition.
if (window.GrDiffBuilderBinary) { return; }
- function GrDiffBuilderBinary(diff, patchRange, commentThreadEls, prefs,
+ function GrDiffBuilderBinary(diff, commentThreadEls, prefs,
outputEl) {
- GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
+ GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
outputEl);
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
index c52a504..f05f4f0 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
@@ -22,9 +22,9 @@
const IMAGE_MIME_PATTERN = /^image\/(bmp|gif|jpeg|jpg|png|tiff|webp)$/;
- function GrDiffBuilderImage(diff, patchRange, commentThreadEls, prefs,
+ function GrDiffBuilderImage(diff, commentThreadEls, prefs,
outputEl, baseImage, revisionImage) {
- GrDiffBuilderSideBySide.call(this, diff, patchRange, commentThreadEls,
+ GrDiffBuilderSideBySide.call(this, diff, commentThreadEls,
prefs, outputEl, []);
this._baseImage = baseImage;
this._revisionImage = revisionImage;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
index da085c2..81cbabb 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-side-by-side.js
@@ -20,9 +20,9 @@
// Prevent redefinition.
if (window.GrDiffBuilderSideBySide) { return; }
- function GrDiffBuilderSideBySide(diff, patchRange, commentThreadEls,
+ function GrDiffBuilderSideBySide(diff, commentThreadEls,
prefs, outputEl, layers) {
- GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
+ GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
outputEl, layers);
}
GrDiffBuilderSideBySide.prototype = Object.create(GrDiffBuilder.prototype);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
index 0657ee4..2dcdee4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-unified.js
@@ -20,9 +20,9 @@
// Prevent redefinition.
if (window.GrDiffBuilderUnified) { return; }
- function GrDiffBuilderUnified(diff, patchRange, commentThreadEls, prefs,
+ function GrDiffBuilderUnified(diff, commentThreadEls, prefs,
outputEl, layers) {
- GrDiffBuilder.call(this, diff, patchRange, commentThreadEls, prefs,
+ GrDiffBuilder.call(this, diff, commentThreadEls, prefs,
outputEl, layers);
}
GrDiffBuilderUnified.prototype = Object.create(GrDiffBuilder.prototype);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index e77eb57..420a14f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -169,8 +169,7 @@
// Stop the processor and syntax layer (if they're running).
this.cancel();
- this._builder = this._getDiffBuilder(
- this.diff, comments.meta.patchRange, prefs);
+ this._builder = this._getDiffBuilder(this.diff, prefs);
this.$.processor.context = prefs.context;
this.$.processor.keyLocations = this._getKeyLocations(comments,
@@ -294,7 +293,7 @@
throw Error(`Invalid preference value: ${pref}`);
},
- _getDiffBuilder(diff, patchRange, prefs) {
+ _getDiffBuilder(diff, prefs) {
if (isNaN(prefs.tab_size) || prefs.tab_size <= 0) {
this._handlePreferenceError('tab size');
return;
@@ -307,19 +306,19 @@
let builder = null;
if (this.isImageDiff) {
- builder = new GrDiffBuilderImage(diff, patchRange,
+ builder = new GrDiffBuilderImage(diff,
this._commentThreadElements, prefs, this.diffElement,
this.baseImage, this.revisionImage);
} else if (diff.binary) {
// If the diff is binary, but not an image.
- return new GrDiffBuilderBinary(diff, patchRange,
+ return new GrDiffBuilderBinary(diff,
this._commentThreadElements, prefs, this.diffElement);
} else if (this.viewMode === DiffViewMode.SIDE_BY_SIDE) {
- builder = new GrDiffBuilderSideBySide(diff, patchRange,
+ builder = new GrDiffBuilderSideBySide(diff,
this._commentThreadElements, prefs, this.diffElement,
this._layers);
} else if (this.viewMode === DiffViewMode.UNIFIED) {
- builder = new GrDiffBuilderUnified(diff, patchRange,
+ builder = new GrDiffBuilderUnified(diff,
this._commentThreadElements, prefs, this.diffElement,
this._layers);
}
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index 6ea48ac..d428f68 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -96,10 +96,9 @@
*/
const REGEX_TAB_OR_SURROGATE_PAIR = /\t|[\uD800-\uDBFF][\uDC00-\uDFFF]/;
- function GrDiffBuilder(diff, patchRange, commentThreadEls, prefs,
+ function GrDiffBuilder(diff, commentThreadEls, prefs,
outputEl, layers) {
this._diff = diff;
- this._patchRange = patchRange;
this._prefs = prefs;
this._outputEl = outputEl;
this.groups = [];
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index c277f34..fd74d55 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -75,8 +75,7 @@
show_tabs: true,
tab_size: 4,
};
- builder = new GrDiffBuilder(
- {content: []}, {left: [], right: []}, [], prefs);
+ builder = new GrDiffBuilder({content: []}, [], prefs);
});
teardown(() => { sandbox.restore(); });
@@ -329,9 +328,7 @@
r5.setAttribute('comment-side', 'right');
r5.setAttribute('line-num', 5);
- builder = new GrDiffBuilder(
- {content: []}, {basePatchNum: 'PARENT', patchNum: '3'}, [l3, l5, r5],
- prefs);
+ builder = new GrDiffBuilder({content: []}, [l3, l5, r5], prefs);
function checkThreadGroupProps(threadGroupEl,
expectedThreadEls) {
@@ -357,8 +354,6 @@
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.LEFT);
checkThreadGroupProps(threadGroupEl, [l5]);
- builder._patchRange.basePatchNum = '1';
-
threadGroupEl = builder._commentThreadGroupForLine(line);
checkThreadGroupProps(threadGroupEl, [l5, r5]);
@@ -370,8 +365,6 @@
builder._commentThreadGroupForLine(line, GrDiffBuilder.Side.RIGHT);
checkThreadGroupProps(threadGroupEl, [r5]);
- builder._patchRange.basePatchNum = 'PARENT';
-
line = new GrDiffLine(GrDiffLine.Type.REMOVE);
line.beforeNumber = 5;
line.afterNumber = 5;
@@ -389,7 +382,7 @@
test('_handlePreferenceError called with invalid preference', () => {
sandbox.stub(element, '_handlePreferenceError');
const prefs = {tab_size: 0};
- element._getDiffBuilder(element.diff, undefined, prefs);
+ element._getDiffBuilder(element.diff, prefs);
assert.isTrue(element._handlePreferenceError.lastCall
.calledWithExactly('tab size'));
});
@@ -947,8 +940,7 @@
outputEl = element.queryEffectiveChildren('#diffTable');
comments = {left: [], right: [], meta: {patchRange: undefined}};
sandbox.stub(element, '_getDiffBuilder', () => {
- const builder = new GrDiffBuilder(
- {content}, undefined, [], prefs, outputEl);
+ const builder = new GrDiffBuilder({content}, [], prefs, outputEl);
sandbox.stub(builder, 'addColumns');
builder.buildSectionElement = function(group) {
const section = document.createElement('stub');
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
index 59c5b1f..fd54af4 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.js
@@ -169,6 +169,10 @@
type: Object,
computed: '_getRevisionInfo(_change)',
},
+ _reviewedFiles: {
+ type: Object,
+ value: () => new Set(),
+ },
},
behaviors: [
@@ -215,6 +219,7 @@
[this.Shortcut.TOGGLE_DIFF_MODE]: '_handleToggleDiffMode',
[this.Shortcut.TOGGLE_FILE_REVIEWED]: '_handleToggleFileReviewed',
[this.Shortcut.EXPAND_ALL_DIFF_CONTEXT]: '_handleExpandAllDiffContext',
+ [this.Shortcut.NEXT_UNREVIEWED_FILE]: '_handleNextUnreviewedFile',
// Final two are actually handled by gr-diff-comment-thread.
[this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
@@ -564,10 +569,18 @@
return {path: fileList[idx]};
},
+ _getReviewedFiles(changeNum, patchNum) {
+ return this.$.restAPI.getReviewedFiles(changeNum, patchNum)
+ .then(files => {
+ this._reviewedFiles = new Set(files);
+ return this._reviewedFiles;
+ });
+ },
+
_getReviewedStatus(editMode, changeNum, patchNum, path) {
if (editMode) { return Promise.resolve(false); }
- return this.$.restAPI.getReviewedFiles(changeNum, patchNum)
- .then(files => files.includes(path));
+ return this._getReviewedFiles(changeNum, patchNum)
+ .then(files => files.has(path));
},
_paramsChanged(value) {
@@ -1025,5 +1038,15 @@
_computeDiffPrefsDisabled(disableDiffPrefs, loggedIn) {
return disableDiffPrefs || !loggedIn;
},
+
+ _handleNextUnreviewedFile(e) {
+ this._setReviewed(true);
+ // Ensure that the currently viewed file always appears in unreviewedFiles
+ // so we resolve the right "next" file.
+ const unreviewedFiles = this._fileList
+ .filter(file =>
+ (file === this._path || !this._reviewedFiles.has(file)));
+ this._navToFile(this._path, unreviewedFiles, 1);
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
index 3a5ca51..0274330 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.html
@@ -67,6 +67,7 @@
kb.bindShortcut(kb.Shortcut.EXPAND_ALL_DIFF_CONTEXT, 'shift+x');
kb.bindShortcut(kb.Shortcut.EXPAND_ALL_COMMENT_THREADS, 'e');
kb.bindShortcut(kb.Shortcut.COLLAPSE_ALL_COMMENT_THREADS, 'shift+e');
+ kb.bindShortcut(kb.Shortcut.NEXT_UNREVIEWED_FILE, 'shift+m');
let element;
let sandbox;
@@ -1127,5 +1128,22 @@
assert.isTrue(setStub.calledOnce);
assert.isTrue(setStub.calledWith(101, 'test-project'));
});
+
+ test('shift+m navigates to next unreviewed file', () => {
+ element._fileList = ['file1', 'file2', 'file3'];
+ element._reviewedFiles = new Set(['file1', 'file2']);
+ element._path = 'file1';
+ const reviewedStub = sandbox.stub(element, '_setReviewed');
+ const navStub = sandbox.stub(element, '_navToFile');
+ MockInteractions.pressAndReleaseKeyOn(element, 77, 'shift', 'm');
+ flushAsynchronousOperations();
+
+ assert.isTrue(reviewedStub.lastCall.args[0]);
+ assert.deepEqual(navStub.lastCall.args, [
+ 'file1',
+ ['file1', 'file3'],
+ 1,
+ ]);
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 4befd2f..62284ad 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -302,8 +302,7 @@
const mock = document.createElement('mock-diff-response');
element.$.diffBuilder._builder = element.$.diffBuilder._getDiffBuilder(
- mock.diffResponse, {left: [], right: []},
- {tab_size: 2, line_length: 80});
+ mock.diffResponse, {tab_size: 2, line_length: 80});
// No thread groups.
assert.isNotOk(element._getThreadGroupForLine(contentEl));
diff --git a/polygerrit-ui/app/elements/gr-app.js b/polygerrit-ui/app/elements/gr-app.js
index e878f7c..f2f06d1 100644
--- a/polygerrit-ui/app/elements/gr-app.js
+++ b/polygerrit-ui/app/elements/gr-app.js
@@ -275,6 +275,8 @@
this.bindShortcut(
this.Shortcut.TOGGLE_FILE_REVIEWED, 'r');
this.bindShortcut(
+ this.Shortcut.NEXT_UNREVIEWED_FILE, 'shift+m');
+ this.bindShortcut(
this.Shortcut.TOGGLE_ALL_INLINE_DIFFS, 'shift+i:keyup');
this.bindShortcut(
this.Shortcut.TOGGLE_INLINE_DIFF, 'i:keyup');
diff --git a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
index 4f80475..4ea8cc7 100644
--- a/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
+++ b/polygerrit-ui/app/elements/shared/gr-icons/gr-icons.html
@@ -48,6 +48,10 @@
<g id="publishEdit"><path d="M5 4v2h14V4H5zm0 10h4v6h6v-6h4l-7-7-7 7z"/></g>
<!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/editor-icons.html -->
<g id="delete"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></g>
+ <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+ <g id="help"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"></path></g>
+ <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+ <g id="info"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"></path></g>
<!-- This SVG is a copy from material.io https://material.io/icons/#ic_hourglass_full-->
<g id="hourglass"><path d="M6 2v6h.01L6 8.01 10 12l-4 4 .01.01H6V22h12v-5.99h-.01L18 16l-4-4 4-3.99-.01-.01H18V2H6z"/><path d="M0 0h24v24H0V0z" fill="none"/></g>
<!-- This is a custom PolyGerrit SVG -->
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 2a1ad9e..d9b0cbf 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
@@ -169,6 +169,16 @@
delete(key) {
this._cache().delete(key);
}
+
+ invalidatePrefix(prefix) {
+ const newMap = new Map();
+ for (const [key, value] of this._cache().entries()) {
+ if (!key.startsWith(prefix)) {
+ newMap.set(key, value);
+ }
+ }
+ this._data.set(window.CANONICAL_PATH, newMap);
+ }
}
Polymer({
@@ -1207,6 +1217,20 @@
return this._sharedFetchPromises[req.url];
},
+ /**
+ * @param {string} prefix
+ */
+ _invalidateSharedFetchPromisesPrefix(prefix) {
+ const newObject = {};
+ Object.entries(this._sharedFetchPromises).forEach(([key, value]) => {
+ if (!key.startsWith(prefix)) {
+ newObject[key] = value;
+ }
+ });
+ this._sharedFetchPromises = newObject;
+ this._cache.invalidatePrefix(prefix);
+ },
+
_isNarrowScreen() {
return window.innerWidth < MAX_UNIFIED_DEFAULT_WINDOW_WIDTH_PX;
},
@@ -1297,21 +1321,27 @@
* @param {function()=} opt_cancelCondition
*/
getChangeDetail(changeNum, opt_errFn, opt_cancelCondition) {
- const options = this.listChangesOptionsToHex(
- this.ListChangesOption.ALL_COMMITS,
- this.ListChangesOption.ALL_REVISIONS,
- this.ListChangesOption.CHANGE_ACTIONS,
- this.ListChangesOption.CURRENT_ACTIONS,
- this.ListChangesOption.DETAILED_LABELS,
- this.ListChangesOption.DOWNLOAD_COMMANDS,
- this.ListChangesOption.MESSAGES,
- this.ListChangesOption.SUBMITTABLE,
- this.ListChangesOption.WEB_LINKS,
- this.ListChangesOption.SKIP_MERGEABLE
- );
- return this._getChangeDetail(
- changeNum, options, opt_errFn, opt_cancelCondition)
- .then(GrReviewerUpdatesParser.parse);
+ const options = [
+ this.ListChangesOption.ALL_COMMITS,
+ this.ListChangesOption.ALL_REVISIONS,
+ this.ListChangesOption.CHANGE_ACTIONS,
+ this.ListChangesOption.CURRENT_ACTIONS,
+ this.ListChangesOption.DETAILED_LABELS,
+ this.ListChangesOption.DOWNLOAD_COMMANDS,
+ this.ListChangesOption.MESSAGES,
+ this.ListChangesOption.SUBMITTABLE,
+ this.ListChangesOption.WEB_LINKS,
+ this.ListChangesOption.SKIP_MERGEABLE,
+ ];
+ return this.getConfig(false).then(config => {
+ if (config.receive && config.receive.enable_signed_push) {
+ options.push(this.ListChangesOption.PUSH_CERTIFICATES);
+ }
+ const optionsHex = this.listChangesOptionsToHex(...options);
+ return this._getChangeDetail(
+ changeNum, optionsHex, opt_errFn, opt_cancelCondition)
+ .then(GrReviewerUpdatesParser.parse);
+ });
},
/**
@@ -1527,25 +1557,20 @@
* @param {string} filter
* @param {number} groupsPerPage
* @param {number=} opt_offset
- * @return {!Promise<?Object>}
*/
- getGroups(filter, groupsPerPage, opt_offset) {
+ _getGroupsUrl(filter, groupsPerPage, opt_offset) {
const offset = opt_offset || 0;
- return this._fetchSharedCacheURL({
- url: `/groups/?n=${groupsPerPage + 1}&S=${offset}` +
- this._computeFilter(filter),
- anonymizedUrl: '/groups/?*',
- });
+ return `/groups/?n=${groupsPerPage + 1}&S=${offset}` +
+ this._computeFilter(filter);
},
/**
* @param {string} filter
* @param {number} reposPerPage
* @param {number=} opt_offset
- * @return {!Promise<?Object>}
*/
- getRepos(filter, reposPerPage, opt_offset) {
+ _getReposUrl(filter, reposPerPage, opt_offset) {
const defaultFilter = 'state:active OR state:read-only';
const namePartDelimiters = /[@.\-\s\/_]/g;
const offset = opt_offset || 0;
@@ -1572,11 +1597,46 @@
filter = filter.trim();
const encodedFilter = encodeURIComponent(filter);
+ return `/projects/?n=${reposPerPage + 1}&S=${offset}` +
+ `&query=${encodedFilter}`;
+ },
+
+ invalidateGroupsCache() {
+ this._invalidateSharedFetchPromisesPrefix('/groups/?');
+ },
+
+ invalidateReposCache(filter, reposPerPage, opt_offset) {
+ this._invalidateSharedFetchPromisesPrefix('/projects/?');
+ },
+
+ /**
+ * @param {string} filter
+ * @param {number} groupsPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
+ getGroups(filter, groupsPerPage, opt_offset) {
+ const url = this._getGroupsUrl(filter, groupsPerPage, opt_offset);
+
+ return this._fetchSharedCacheURL({
+ url,
+ anonymizedUrl: '/groups/?*',
+ });
+ },
+
+ /**
+ * @param {string} filter
+ * @param {number} reposPerPage
+ * @param {number=} opt_offset
+ * @return {!Promise<?Object>}
+ */
+ getRepos(filter, reposPerPage, opt_offset) {
+ const url = this._getReposUrl(filter, reposPerPage, opt_offset);
+
// TODO(kaspern): Rename rest api from /projects/ to /repos/ once backend
// supports it.
return this._fetchSharedCacheURL({
- url: `/projects/?n=${reposPerPage + 1}&S=${offset}` +
- `&query=${encodedFilter}`,
+ url,
anonymizedUrl: '/projects/?*',
});
},
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
index eaac5ef..667f24c 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface_test.html
@@ -96,6 +96,18 @@
});
});
+ test('cache invalidation', () => {
+ element._cache.set('/foo/bar', 1);
+ element._cache.set('/bar', 2);
+ element._sharedFetchPromises['/foo/bar'] = 3;
+ element._sharedFetchPromises['/bar'] = 4;
+ element._invalidateSharedFetchPromisesPrefix('/foo/');
+ assert.isFalse(element._cache.has('/foo/bar'));
+ assert.isTrue(element._cache.has('/bar'));
+ assert.isUndefined(element._sharedFetchPromises['/foo/bar']);
+ assert.strictEqual(4, element._sharedFetchPromises['/bar']);
+ });
+
test('params are properly encoded', () => {
let url = element._urlWithParams('/path/', {
sp: 'hola',
@@ -722,15 +734,6 @@
assert.deepEqual(element._send.lastCall.args[0].body, {token: 'foo'});
});
- test('GrReviewerUpdatesParser.parse is used', () => {
- sandbox.stub(GrReviewerUpdatesParser, 'parse').returns(
- Promise.resolve('foo'));
- return element.getChangeDetail(42).then(result => {
- assert.isTrue(GrReviewerUpdatesParser.parse.calledOnce);
- assert.equal(result, 'foo');
- });
- });
-
test('setAccountStatus', () => {
sandbox.stub(element, '_send').returns(Promise.resolve('OOO'));
element._cache.set('/accounts/self/detail', {});
@@ -935,6 +938,31 @@
});
});
+ test('normal use', () => {
+ const defaultQuery = 'state%3Aactive%20OR%20state%3Aread-only';
+
+ assert.equal(element._getReposUrl('test', 25),
+ '/projects/?n=26&S=0&query=test');
+
+ assert.equal(element._getReposUrl(null, 25),
+ `/projects/?n=26&S=0&query=${defaultQuery}`);
+
+ assert.equal(element._getReposUrl('test', 25, 25),
+ '/projects/?n=26&S=25&query=test');
+ });
+
+ test('invalidateReposCache', () => {
+ const url = '/projects/?n=26&S=0&query=test';
+
+ element._cache.set(url, {});
+
+ element.invalidateReposCache('test', 25);
+
+ assert.isUndefined(element._sharedFetchPromises[url]);
+
+ assert.isFalse(element._cache.has(url));
+ });
+
suite('getRepos', () => {
const defaultQuery = 'state%3Aactive%20OR%20state%3Aread-only';
@@ -999,11 +1027,57 @@
});
});
- test('getGroups filter regex', () => {
- sandbox.stub(element, '_fetchSharedCacheURL');
- element.getGroups('^test.*', 25);
- assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
- '/groups/?n=26&S=0&r=%5Etest.*');
+ test('_getGroupsUrl normal use', () => {
+ assert.equal(element._getGroupsUrl('test', 25),
+ '/groups/?n=26&S=0&m=test');
+
+ assert.equal(element._getGroupsUrl(null, 25),
+ '/groups/?n=26&S=0');
+
+ assert.equal(element._getGroupsUrl('test', 25, 25),
+ '/groups/?n=26&S=25&m=test');
+ });
+
+ test('invalidateGroupsCache', () => {
+ const url = '/groups/?n=26&S=0&m=test';
+
+ element._cache.set(url, {});
+
+ element.invalidateGroupsCache('test', 25);
+
+ assert.isUndefined(element._sharedFetchPromises[url]);
+
+ assert.isFalse(element._cache.has(url));
+ });
+
+ suite('getGroups', () => {
+ setup(() => {
+ sandbox.stub(element, '_fetchSharedCacheURL');
+ });
+
+ test('normal use', () => {
+ element.getGroups('test', 25);
+ assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
+ '/groups/?n=26&S=0&m=test');
+
+ element.getGroups(null, 25);
+ assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
+ '/groups/?n=26&S=0');
+
+ element.getGroups('test', 25, 25);
+ assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
+ '/groups/?n=26&S=25&m=test');
+ });
+
+ test('regex', () => {
+ element.getGroups('^test.*', 25);
+ assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
+ '/groups/?n=26&S=0&r=%5Etest.*');
+
+ element.getGroups('^test.*', 25, 25);
+ assert.equal(element._fetchSharedCacheURL.lastCall.args[0].url,
+ '/groups/?n=26&S=25&r=%5Etest.*');
+ });
});
test('gerrit auth is used', () => {
@@ -1031,7 +1105,49 @@
});
});
- suite('_getChangeDetail', () => {
+ suite('getChangeDetail', () => {
+ suite('change detail options', () => {
+ let toHexStub;
+
+ setup(() => {
+ toHexStub = sandbox.stub(element, 'listChangesOptionsToHex',
+ options => 'deadbeef');
+ sandbox.stub(element, '_getChangeDetail',
+ async (changeNum, options) => ({changeNum, options}));
+ });
+
+ test('signed pushes disabled', async () => {
+ const {PUSH_CERTIFICATES} = element.ListChangesOption;
+ sandbox.stub(element, 'getConfig', async () => ({}));
+ const {changeNum, options} = await element.getChangeDetail(123);
+ assert.strictEqual(123, changeNum);
+ assert.strictEqual('deadbeef', options);
+ assert.isTrue(toHexStub.calledOnce);
+ assert.isFalse(toHexStub.lastCall.args.includes(PUSH_CERTIFICATES));
+ });
+
+ test('signed pushes enabled', async () => {
+ const {PUSH_CERTIFICATES} = element.ListChangesOption;
+ sandbox.stub(element, 'getConfig', async () => {
+ return {receive: {enable_signed_push: true}};
+ });
+ const {changeNum, options} = await element.getChangeDetail(123);
+ assert.strictEqual(123, changeNum);
+ assert.strictEqual('deadbeef', options);
+ assert.isTrue(toHexStub.calledOnce);
+ assert.isTrue(toHexStub.lastCall.args.includes(PUSH_CERTIFICATES));
+ });
+ });
+
+ test('GrReviewerUpdatesParser.parse is used', () => {
+ sandbox.stub(GrReviewerUpdatesParser, 'parse').returns(
+ Promise.resolve('foo'));
+ return element.getChangeDetail(42).then(result => {
+ assert.isTrue(GrReviewerUpdatesParser.parse.calledOnce);
+ assert.equal(result, 'foo');
+ });
+ });
+
test('_getChangeDetail passes params to ETags decorator', () => {
const changeNum = 4321;
element._projectLookup[changeNum] = 'test';