Merge changes I0da14436,I1e15767f
* changes:
Remove workaround regarding newlines on GWT UI
Fix diff regarding newline at end of file
diff --git a/0001-Replace-native-http-git-_archive-with-Skylark-rules.patch b/0001-Replace-native-http-git-_archive-with-Skylark-rules.patch
deleted file mode 100644
index 3ccf5cd..0000000
--- a/0001-Replace-native-http-git-_archive-with-Skylark-rules.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-Date: Wed, 30 May 2018 21:22:18 +0200
-Subject: [PATCH] Replace native {http,git}_archive with Skylark rules
-
-See [1] for more details.
-
-Test Plan:
-
-* Apply this CL on Bazel master: [2] and build bazel
-* Run with this custom built bazel version:
-
- $ bazel test //javatests/...
- $ bazel test //closure/...
-
-[1] https://groups.google.com/d/topic/bazel-discuss/dO2MHQLwJF0/discussion
-[2] https://bazel-review.googlesource.com/#/c/bazel/+/55932/
----
- closure/repositories.bzl | 23 ++++++++++++-----------
- 1 file changed, 12 insertions(+), 11 deletions(-)
-
-diff --git a/closure/repositories.bzl b/closure/repositories.bzl
-index 9b84a72..2816fb6 100644
---- closure/repositories.bzl
-+++ closure/repositories.bzl
-@@ -14,6 +14,7 @@
-
- """External dependencies for Closure Rules."""
-
-+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
- load("//closure/private:java_import_external.bzl", "java_import_external")
- load("//closure/private:platform_http_file.bzl", "platform_http_file")
- load("//closure:filegroup_external.bzl", "filegroup_external")
-@@ -405,7 +406,7 @@ def com_google_common_html_types():
- )
-
- def com_google_common_html_types_html_proto():
-- native.http_file(
-+ http_file(
- name = "com_google_common_html_types_html_proto",
- sha256 = "6ece202f11574e37d0c31d9cf2e9e11a0dbc9218766d50d211059ebd495b49c3",
- urls = [
-@@ -633,7 +634,7 @@ def com_google_javascript_closure_compiler():
-
- def com_google_javascript_closure_library():
- # After updating: bazel run //closure/library:regenerate -- "$PWD"
-- native.new_http_archive(
-+ http_archive(
- name = "com_google_javascript_closure_library",
- urls = [
- "https://mirror.bazel.build/github.com/google/closure-library/archive/v20180405.tar.gz",
-@@ -658,7 +659,7 @@ def com_google_jsinterop_annotations():
-
- def com_google_protobuf():
- # Note: Protobuf 3.6.0+ is going to use C++11
-- native.http_archive(
-+ http_archive(
- name = "com_google_protobuf",
- strip_prefix = "protobuf-3.5.1",
- sha256 = "826425182ee43990731217b917c5c3ea7190cfda141af4869e6d4ad9085a740f",
-@@ -669,7 +670,7 @@ def com_google_protobuf():
- )
-
- def com_google_protobuf_js():
-- native.new_http_archive(
-+ http_archive(
- name = "com_google_protobuf_js",
- urls = [
- "https://mirror.bazel.build/github.com/google/protobuf/archive/v3.5.1.tar.gz",
-@@ -722,7 +723,7 @@ def com_google_template_soy():
- )
-
- def com_google_template_soy_jssrc():
-- native.new_http_archive(
-+ http_archive(
- name = "com_google_template_soy_jssrc",
- sha256 = "c76ab4cb6e46a7c76336640b3c40d6897b420209a6c0905cdcd32533dda8126a",
- urls = [
-@@ -757,7 +758,7 @@ def com_squareup_javapoet():
- )
-
- def fonts_noto_hinted_deb():
-- native.http_file(
-+ http_file(
- name = "fonts_noto_hinted_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/f/fonts-noto/fonts-noto-hinted_20161116-1_all.deb",
-@@ -767,7 +768,7 @@ def fonts_noto_hinted_deb():
- )
-
- def fonts_noto_mono_deb():
-- native.http_file(
-+ http_file(
- name = "fonts_noto_mono_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/f/fonts-noto/fonts-noto-mono_20161116-1_all.deb",
-@@ -801,7 +802,7 @@ def javax_inject():
- )
-
- def libexpat_amd64_deb():
-- native.http_file(
-+ http_file(
- name = "libexpat_amd64_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/e/expat/libexpat1_2.1.0-6+deb8u3_amd64.deb",
-@@ -811,7 +812,7 @@ def libexpat_amd64_deb():
- )
-
- def libfontconfig_amd64_deb():
-- native.http_file(
-+ http_file(
- name = "libfontconfig_amd64_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/f/fontconfig/libfontconfig1_2.11.0-6.3+deb8u1_amd64.deb",
-@@ -821,7 +822,7 @@ def libfontconfig_amd64_deb():
- )
-
- def libfreetype_amd64_deb():
-- native.http_file(
-+ http_file(
- name = "libfreetype_amd64_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/f/freetype/libfreetype6_2.5.2-3+deb8u1_amd64.deb",
-@@ -831,7 +832,7 @@ def libfreetype_amd64_deb():
- )
-
- def libpng_amd64_deb():
-- native.http_file(
-+ http_file(
- name = "libpng_amd64_deb",
- urls = [
- "https://mirror.bazel.build/http.us.debian.org/debian/pool/main/libp/libpng/libpng12-0_1.2.50-2+deb8u2_amd64.deb",
---
-2.16.3
-
diff --git a/0002-Bump-Dagger-to-2.14.1-to-support-Java-9.patch b/0002-Bump-Dagger-to-2.14.1-to-support-Java-9.patch
deleted file mode 100644
index df6780d..0000000
--- a/0002-Bump-Dagger-to-2.14.1-to-support-Java-9.patch
+++ /dev/null
@@ -1,116 +0,0 @@
-Date: Thu, 21 Jun 2018 19:29:13 +0200
-Subject: [PATCH 2/2] Bump Dagger to 2.14.1 to support Java 9
-
-Closes #275
----
- closure/repositories.bzl | 41 +++++++++++++++++++++++++++++------------
- 1 file changed, 29 insertions(+), 12 deletions(-)
-
-diff --git a/closure/repositories.bzl b/closure/repositories.bzl
-index 2816fb6..fe63b6f 100644
---- closure/repositories.bzl
-+++ closure/repositories.bzl
-@@ -35,6 +35,7 @@ def closure_repositories(
- omit_com_google_dagger=False,
- omit_com_google_dagger_compiler=False,
- omit_com_google_dagger_producers=False,
-+ omit_com_google_dagger_spi=False,
- omit_com_google_errorprone_error_prone_annotations=False,
- omit_com_google_errorprone_javac_shaded=False,
- omit_com_google_guava=False,
-@@ -101,6 +102,8 @@ def closure_repositories(
- com_google_dagger_compiler()
- if not omit_com_google_dagger_producers:
- com_google_dagger_producers()
-+ if not omit_com_google_dagger_spi:
-+ com_google_dagger_spi()
- if not omit_com_google_errorprone_error_prone_annotations:
- com_google_errorprone_error_prone_annotations()
- if not omit_com_google_errorprone_javac_shaded:
-@@ -418,10 +421,10 @@ def com_google_common_html_types_html_proto():
- def com_google_dagger():
- java_import_external(
- name = "com_google_dagger",
-- jar_sha256 = "8b7806518bed270950002158934fbd8281725ee09909442f2f22b58520b667a7",
-+ jar_sha256 = "374cfee26c9c93f44caa1946583c9edc135bb9a42838476522551ec46aa55c7c",
- jar_urls = [
-- "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger/2.9/dagger-2.9.jar",
-- "https://repo1.maven.org/maven2/com/google/dagger/dagger/2.9/dagger-2.9.jar",
-+ "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger/2.14.1/dagger-2.14.1.jar",
-+ "https://repo1.maven.org/maven2/com/google/dagger/dagger/2.14.1/dagger-2.14.1.jar",
- ],
- licenses = ["notice"], # Apache 2.0
- deps = ["@javax_inject"],
-@@ -441,17 +444,20 @@ def com_google_dagger():
- def com_google_dagger_compiler():
- java_import_external(
- name = "com_google_dagger_compiler",
-- jar_sha256 = "afe356def27710db5b60cad8e7a6c06510dc3d3b854f30397749cbf0d0e71315",
-+ jar_sha256 = "ff16d55273e375349537fc82292b00de04d8a2caca2d4aa6c642692b1a68194d",
- jar_urls = [
-- "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.9/dagger-compiler-2.9.jar",
-- "https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.9/dagger-compiler-2.9.jar",
-+ "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.14.1/dagger-compiler-2.14.1.jar",
-+ "https://repo1.maven.org/maven2/com/google/dagger/dagger-compiler/2.14.1/dagger-compiler-2.14.1.jar",
- ],
- licenses = ["notice"], # Apache 2.0
- deps = [
- "@com_google_code_findbugs_jsr305",
- "@com_google_dagger//:runtime",
- "@com_google_dagger_producers//:runtime",
-+ "@com_google_dagger_spi",
- "@com_google_guava",
-+ "@com_google_java_format",
-+ "@com_squareup_javapoet",
- ],
- extra_build_file_content = "\n".join([
- "java_plugin(",
-@@ -471,10 +477,10 @@ def com_google_dagger_compiler():
- def com_google_dagger_producers():
- java_import_external(
- name = "com_google_dagger_producers",
-- jar_sha256 = "b452dc1b95dd02f6272e97b15d1bd35d92b5f484a7d69bb73887b6c6699d8843",
-+ jar_sha256 = "96f950bc4b94d013b0c538632a4bc630f33eda8b01f63ae752b76c5e48783859",
- jar_urls = [
-- "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.9/dagger-producers-2.9.jar",
-- "https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.9/dagger-producers-2.9.jar",
-+ "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.14.1/dagger-producers-2.14.1.jar",
-+ "https://repo1.maven.org/maven2/com/google/dagger/dagger-producers/2.14.1/dagger-producers-2.14.1.jar",
- ],
- licenses = ["notice"], # Apache 2.0
- deps = [
-@@ -495,6 +501,17 @@ def com_google_dagger_producers():
- ]),
- )
-
-+def com_google_dagger_spi():
-+ java_import_external(
-+ name = "com_google_dagger_spi",
-+ jar_sha256 = "6a20d6c6620fefe50747e9e910e0d0c178cf39d76b67ccffb505ac9a167302cb",
-+ jar_urls = [
-+ "https://mirror.bazel.build/repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.14.1/dagger-spi-2.14.1.jar",
-+ "https://repo1.maven.org/maven2/com/google/dagger/dagger-spi/2.14.1/dagger-spi-2.14.1.jar",
-+ ],
-+ licenses = ["notice"], # Apache 2.0
-+ )
-+
- def com_google_errorprone_error_prone_annotations():
- java_import_external(
- name = "com_google_errorprone_error_prone_annotations",
-@@ -749,10 +766,10 @@ def com_ibm_icu_icu4j():
- def com_squareup_javapoet():
- java_import_external(
- name = "com_squareup_javapoet",
-- jar_sha256 = "2f671d5f056f04922feff78dd60c34979fc9863b16ad706551a9b68842c1a3d0",
-+ jar_sha256 = "5bb5abdfe4366c15c0da3332c57d484e238bd48260d6f9d6acf2b08fdde1efea",
- jar_urls = [
-- "https://mirror.bazel.build/repo1.maven.org/maven2/com/squareup/javapoet/1.7.0/javapoet-1.7.0.jar",
-- "https://repo1.maven.org/maven2/com/squareup/javapoet/1.7.0/javapoet-1.7.0.jar",
-+ "https://mirror.bazel.build/repo1.maven.org/maven2/com/squareup/javapoet/1.9.0/javapoet-1.9.0.jar",
-+ "https://repo1.maven.org/maven2/com/squareup/javapoet/1.9.0/javapoet-1.9.0.jar",
- ],
- licenses = ["notice"], # Apache 2.0
- )
---
-2.16.3
-
diff --git a/Documentation/dev-plugins.txt b/Documentation/dev-plugins.txt
index 505d4b7..5c008c7 100644
--- a/Documentation/dev-plugins.txt
+++ b/Documentation/dev-plugins.txt
@@ -2871,6 +2871,17 @@
Plugin authors should also consider binding their SubmitRule using a `Gerrit-BatchModule`.
See link:dev-plugins.html[Batch runtime] for more informations.
+
+The SubmitRule extension point allows you to write complex rules, but writing
+small self-contained rules should be preferred: doing so allows end users to
+compose several rules to form more complex submit checks.
+
+The `SubmitRequirement` class allows rules to communicate what the user needs
+to change in order to be compliant. These requirements should be kept once they
+are met, but marked as `OK`. If the requirements were not displayed, reviewers
+would need to use their precious time to manually check that they were met.
+
+
== SEE ALSO
* link:js-api.html[JavaScript API]
diff --git a/Documentation/user-search-projects.txt b/Documentation/user-search-projects.txt
index ba20adb..11c1326 100644
--- a/Documentation/user-search-projects.txt
+++ b/Documentation/user-search-projects.txt
@@ -24,6 +24,11 @@
Matches projects whose description contains 'DESCRIPTION', using a
full-text search.
+[[state]]
+state:'STATE'::
++
+Matches project's state. Can be either 'active' or 'read-only'.
+
== Magical Operators
[[is-visible]]
diff --git a/WORKSPACE b/WORKSPACE
index 70200d1..dfe2a45 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -14,19 +14,9 @@
http_archive(
name = "io_bazel_rules_closure",
- build_file_content = "\n".join([
- "exports_files([",
- " \"0001-Replace-native-http-git-_archive-with-Skylark-rules.patch\",",
- " \"0002-Bump-Dagger-to-2.14.1-to-support-Java-9.patch\",",
- "])",
- ]),
- patches = [
- "//:0001-Replace-native-http-git-_archive-with-Skylark-rules.patch",
- "//:0002-Bump-Dagger-to-2.14.1-to-support-Java-9.patch",
- ],
- sha256 = "a80acb69c63d5f6437b099c111480a4493bad4592015af2127a2f49fb7512d8d",
- strip_prefix = "rules_closure-0.7.0",
- url = "https://github.com/bazelbuild/rules_closure/archive/0.7.0.tar.gz",
+ sha256 = "4dd84dd2bdd6c9f56cb5a475d504ea31d199c34309e202e9379501d01c3067e5",
+ strip_prefix = "rules_closure-3103a773820b59b76345f94c231cb213e0d404e2",
+ url = "https://github.com/bazelbuild/rules_closure/archive/3103a773820b59b76345f94c231cb213e0d404e2.tar.gz",
)
# File is specific to Polymer and copied from the Closure Github -- should be
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index c0b4df1..960b558 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -68,6 +68,8 @@
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
import com.google.gerrit.mail.Address;
import com.google.gerrit.mail.EmailHeader;
import com.google.gerrit.reviewdb.client.Account;
@@ -274,6 +276,7 @@
@Inject private ChangeIndexCollection changeIndexes;
@Inject private AccountIndexCollection accountIndexes;
+ @Inject private ProjectIndexCollection projectIndexes;
@Inject private EventRecorder.Factory eventRecorderFactory;
@Inject private InProcessProtocol inProcessProtocol;
@Inject private Provider<AnonymousUser> anonymousUser;
@@ -900,6 +903,41 @@
};
}
+ protected AutoCloseable disableProjectIndex() {
+ disableProjectIndexWrites();
+ ProjectIndex searchIndex = projectIndexes.getSearchIndex();
+ if (!(searchIndex instanceof DisabledProjectIndex)) {
+ projectIndexes.setSearchIndex(new DisabledProjectIndex(searchIndex), false);
+ }
+
+ return new AutoCloseable() {
+ @Override
+ public void close() {
+ enableProjectIndexWrites();
+ ProjectIndex searchIndex = projectIndexes.getSearchIndex();
+ if (searchIndex instanceof DisabledProjectIndex) {
+ projectIndexes.setSearchIndex(((DisabledProjectIndex) searchIndex).unwrap(), false);
+ }
+ }
+ };
+ }
+
+ protected void disableProjectIndexWrites() {
+ for (ProjectIndex i : projectIndexes.getWriteIndexes()) {
+ if (!(i instanceof DisabledProjectIndex)) {
+ projectIndexes.addWriteIndex(new DisabledProjectIndex(i));
+ }
+ }
+ }
+
+ protected void enableProjectIndexWrites() {
+ for (ProjectIndex i : projectIndexes.getWriteIndexes()) {
+ if (i instanceof DisabledProjectIndex) {
+ projectIndexes.addWriteIndex(((DisabledProjectIndex) i).unwrap());
+ }
+ }
+ }
+
protected static Gson newGson() {
return OutputFormat.JSON_COMPACT.newGson();
}
diff --git a/java/com/google/gerrit/acceptance/BUILD b/java/com/google/gerrit/acceptance/BUILD
index efca382..0214cea 100644
--- a/java/com/google/gerrit/acceptance/BUILD
+++ b/java/com/google/gerrit/acceptance/BUILD
@@ -99,6 +99,7 @@
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/httpd",
"//java/com/google/gerrit/index",
+ "//java/com/google/gerrit/index/project",
"//java/com/google/gerrit/lucene",
"//java/com/google/gerrit/mail",
"//java/com/google/gerrit/metrics",
diff --git a/java/com/google/gerrit/acceptance/DisabledProjectIndex.java b/java/com/google/gerrit/acceptance/DisabledProjectIndex.java
new file mode 100644
index 0000000..2524a76
--- /dev/null
+++ b/java/com/google/gerrit/acceptance/DisabledProjectIndex.java
@@ -0,0 +1,76 @@
+// 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.gerrit.index.QueryOptions;
+import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.query.DataSource;
+import com.google.gerrit.index.query.Predicate;
+import com.google.gerrit.reviewdb.client.Project;
+
+/**
+ * This class wraps an index and assumes the search index can't handle any queries. However, it does
+ * return the current schema as the assumption is that we need a search index for starting Gerrit in
+ * the first place and only later lose the index connection (making it so that we can't send
+ * requests there anymore).
+ */
+public class DisabledProjectIndex implements ProjectIndex {
+ private final ProjectIndex index;
+
+ public DisabledProjectIndex(ProjectIndex index) {
+ this.index = index;
+ }
+
+ public ProjectIndex unwrap() {
+ return index;
+ }
+
+ @Override
+ public Schema<ProjectData> getSchema() {
+ return index.getSchema();
+ }
+
+ @Override
+ public void close() {
+ index.close();
+ }
+
+ @Override
+ public void replace(ProjectData obj) {
+ throw new UnsupportedOperationException("ProjectIndex is disabled");
+ }
+
+ @Override
+ public void delete(Project.NameKey key) {
+ throw new UnsupportedOperationException("ProjectIndex is disabled");
+ }
+
+ @Override
+ public void deleteAll() {
+ throw new UnsupportedOperationException("ProjectIndex is disabled");
+ }
+
+ @Override
+ public DataSource<ProjectData> getSource(Predicate<ProjectData> p, QueryOptions opts) {
+ throw new UnsupportedOperationException("ProjectIndex is disabled");
+ }
+
+ @Override
+ public void markReady(boolean ready) {
+ throw new UnsupportedOperationException("ProjectIndex is disabled");
+ }
+}
diff --git a/java/com/google/gerrit/acceptance/ProjectResetter.java b/java/com/google/gerrit/acceptance/ProjectResetter.java
index f4a8da3..1fed8f8 100644
--- a/java/com/google/gerrit/acceptance/ProjectResetter.java
+++ b/java/com/google/gerrit/acceptance/ProjectResetter.java
@@ -23,6 +23,7 @@
import com.google.common.collect.MultimapBuilder;
import com.google.common.collect.Sets;
import com.google.gerrit.common.Nullable;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.Project;
@@ -32,7 +33,6 @@
import com.google.gerrit.server.account.GroupIncludeCache;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.index.RefState;
import com.google.gerrit.server.index.account.AccountIndexer;
import com.google.gerrit.server.index.group.GroupIndexer;
import com.google.gerrit.server.project.ProjectCache;
diff --git a/java/com/google/gerrit/common/data/GroupReference.java b/java/com/google/gerrit/common/data/GroupReference.java
index 8060659..cfaad17 100644
--- a/java/com/google/gerrit/common/data/GroupReference.java
+++ b/java/com/google/gerrit/common/data/GroupReference.java
@@ -61,6 +61,9 @@
}
public void setName(String newName) {
+ if (newName == null) {
+ throw new NullPointerException();
+ }
this.name = newName;
}
diff --git a/java/com/google/gerrit/httpd/BUILD b/java/com/google/gerrit/httpd/BUILD
index bbb5b66..3e71098 100644
--- a/java/com/google/gerrit/httpd/BUILD
+++ b/java/com/google/gerrit/httpd/BUILD
@@ -13,6 +13,7 @@
"//java/com/google/gerrit/metrics",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/audit",
"//java/com/google/gerrit/server/git/receive",
"//java/com/google/gerrit/server/ioutil",
"//java/com/google/gerrit/server/restapi",
diff --git a/java/com/google/gerrit/httpd/auth/oauth/BUILD b/java/com/google/gerrit/httpd/auth/oauth/BUILD
index 96726ad..7315ce1 100644
--- a/java/com/google/gerrit/httpd/auth/oauth/BUILD
+++ b/java/com/google/gerrit/httpd/auth/oauth/BUILD
@@ -10,6 +10,7 @@
"//java/com/google/gerrit/httpd",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/audit",
"//lib:gson",
"//lib:guava",
"//lib:gwtorm",
diff --git a/java/com/google/gerrit/httpd/auth/openid/BUILD b/java/com/google/gerrit/httpd/auth/openid/BUILD
index bfb2551..f80e9d5 100644
--- a/java/com/google/gerrit/httpd/auth/openid/BUILD
+++ b/java/com/google/gerrit/httpd/auth/openid/BUILD
@@ -13,6 +13,7 @@
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/util/http",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/audit",
"//lib:guava",
"//lib:gwtorm",
"//lib:servlet-api-3_1",
diff --git a/java/com/google/gerrit/httpd/init/BUILD b/java/com/google/gerrit/httpd/init/BUILD
index 292ceff..d557c0e 100644
--- a/java/com/google/gerrit/httpd/init/BUILD
+++ b/java/com/google/gerrit/httpd/init/BUILD
@@ -18,6 +18,7 @@
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server:module",
"//java/com/google/gerrit/server/api",
+ "//java/com/google/gerrit/server/audit",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/cache/mem",
"//java/com/google/gerrit/server/git/receive",
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 9ce7690..8e380f5 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -47,6 +47,7 @@
import com.google.gerrit.server.account.AccountDeactivator;
import com.google.gerrit.server.account.InternalAccountDirectory;
import com.google.gerrit.server.api.GerritApiModule;
+import com.google.gerrit.server.audit.AuditModule;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.ChangeCleanupRunner;
@@ -342,6 +343,7 @@
modules.add(new SmtpEmailSender.Module());
modules.add(new SignedTokenEmailTokenVerifier.Module());
modules.add(new LocalMergeSuperSetComputation.Module());
+ modules.add(new AuditModule());
// Plugin module needs to be inserted *before* the index module.
// There is the concept of LifecycleModule, in Gerrit's own extension
diff --git a/java/com/google/gerrit/index/BUILD b/java/com/google/gerrit/index/BUILD
index 2442b593..6604ca1 100644
--- a/java/com/google/gerrit/index/BUILD
+++ b/java/com/google/gerrit/index/BUILD
@@ -37,6 +37,7 @@
"//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/metrics",
+ "//java/com/google/gerrit/reviewdb:server",
"//lib:guava",
"//lib:gwtjsonrpc",
"//lib:gwtorm",
diff --git a/java/com/google/gerrit/server/index/RefState.java b/java/com/google/gerrit/index/RefState.java
similarity index 98%
rename from java/com/google/gerrit/server/index/RefState.java
rename to java/com/google/gerrit/index/RefState.java
index 6b893f0..f0e465d 100644
--- a/java/com/google/gerrit/server/index/RefState.java
+++ b/java/com/google/gerrit/index/RefState.java
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.index;
+package com.google.gerrit.index;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkArgument;
diff --git a/java/com/google/gerrit/index/project/ProjectData.java b/java/com/google/gerrit/index/project/ProjectData.java
index 9d6b571..7365660 100644
--- a/java/com/google/gerrit/index/project/ProjectData.java
+++ b/java/com/google/gerrit/index/project/ProjectData.java
@@ -14,23 +14,43 @@
package com.google.gerrit.index.project;
+import static com.google.common.collect.ImmutableList.toImmutableList;
+
import com.google.common.collect.ImmutableList;
import com.google.gerrit.reviewdb.client.Project;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
public class ProjectData {
private final Project project;
- private final ImmutableList<Project.NameKey> ancestors;
+ private final Optional<ProjectData> parent;
- public ProjectData(Project project, Iterable<Project.NameKey> ancestors) {
+ public ProjectData(Project project, Optional<ProjectData> parent) {
this.project = project;
- this.ancestors = ImmutableList.copyOf(ancestors);
+ this.parent = parent;
}
public Project getProject() {
return project;
}
- public ImmutableList<Project.NameKey> getAncestors() {
- return ancestors;
+ public Optional<ProjectData> getParent() {
+ return parent;
+ }
+
+ /** Returns all {@link ProjectData} in the hierarchy starting with the current one. */
+ public ImmutableList<ProjectData> tree() {
+ List<ProjectData> parents = new ArrayList<>();
+ Optional<ProjectData> curr = Optional.of(this);
+ while (curr.isPresent()) {
+ parents.add(curr.get());
+ curr = curr.get().parent;
+ }
+ return ImmutableList.copyOf(parents);
+ }
+
+ public ImmutableList<String> getParentNames() {
+ return tree().stream().skip(1).map(p -> p.getProject().getName()).collect(toImmutableList());
}
}
diff --git a/java/com/google/gerrit/index/project/ProjectField.java b/java/com/google/gerrit/index/project/ProjectField.java
index 1c2f629b..5e484b2 100644
--- a/java/com/google/gerrit/index/project/ProjectField.java
+++ b/java/com/google/gerrit/index/project/ProjectField.java
@@ -14,23 +14,30 @@
package com.google.gerrit.index.project;
+import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.gerrit.index.FieldDef.exact;
import static com.google.gerrit.index.FieldDef.fullText;
import static com.google.gerrit.index.FieldDef.prefix;
+import static com.google.gerrit.index.FieldDef.storedOnly;
-import com.google.common.collect.Iterables;
import com.google.gerrit.index.FieldDef;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.index.SchemaUtil;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
/** Index schema for projects. */
public class ProjectField {
+ private static byte[] toRefState(Project project) {
+ return RefState.create(RefNames.REFS_CONFIG, project.getConfigRefState())
+ .toByteArray(project.getNameKey());
+ }
public static final FieldDef<ProjectData, String> NAME =
exact("name").stored().build(p -> p.getProject().getName());
public static final FieldDef<ProjectData, String> DESCRIPTION =
- fullText("description").build(p -> p.getProject().getDescription());
+ fullText("description").stored().build(p -> p.getProject().getDescription());
public static final FieldDef<ProjectData, String> PARENT_NAME =
exact("parent_name").build(p -> p.getProject().getParentName());
@@ -38,7 +45,26 @@
public static final FieldDef<ProjectData, Iterable<String>> NAME_PART =
prefix("name_part").buildRepeatable(p -> SchemaUtil.getNameParts(p.getProject().getName()));
+ public static final FieldDef<ProjectData, String> STATE =
+ exact("state").stored().build(p -> p.getProject().getState().name());
+
public static final FieldDef<ProjectData, Iterable<String>> ANCESTOR_NAME =
- exact("ancestor_name")
- .buildRepeatable(p -> Iterables.transform(p.getAncestors(), Project.NameKey::get));
+ exact("ancestor_name").buildRepeatable(p -> p.getParentNames());
+
+ /**
+ * All values of all refs that were used in the course of indexing this document. This covers
+ * {@code refs/meta/config} of the current project and all of its parents.
+ *
+ * <p>Emitted as UTF-8 encoded strings of the form {@code project:ref/name:[hex sha]}.
+ */
+ public static final FieldDef<ProjectData, Iterable<byte[]>> REF_STATE =
+ storedOnly("ref_state")
+ .buildRepeatable(
+ projectData ->
+ projectData
+ .tree()
+ .stream()
+ .filter(p -> p.getProject().getConfigRefState() != null)
+ .map(p -> toRefState(p.getProject()))
+ .collect(toImmutableList()));
}
diff --git a/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
index cbea4fe..07b5adb 100644
--- a/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
+++ b/java/com/google/gerrit/index/project/ProjectSchemaDefinitions.java
@@ -21,6 +21,7 @@
public class ProjectSchemaDefinitions extends SchemaDefinitions<ProjectData> {
+ @Deprecated
static final Schema<ProjectData> V1 =
schema(
ProjectField.NAME,
@@ -29,6 +30,8 @@
ProjectField.NAME_PART,
ProjectField.ANCESTOR_NAME);
+ static final Schema<ProjectData> V2 = schema(V1, ProjectField.STATE, ProjectField.REF_STATE);
+
public static final ProjectSchemaDefinitions INSTANCE = new ProjectSchemaDefinitions();
private ProjectSchemaDefinitions() {
diff --git a/java/com/google/gerrit/pgm/BUILD b/java/com/google/gerrit/pgm/BUILD
index 95570ec..64dd1d8 100644
--- a/java/com/google/gerrit/pgm/BUILD
+++ b/java/com/google/gerrit/pgm/BUILD
@@ -36,6 +36,7 @@
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server:module",
"//java/com/google/gerrit/server/api",
+ "//java/com/google/gerrit/server/audit",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/cache/mem",
"//java/com/google/gerrit/server/git/receive",
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index c38e7f5..517787c 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -56,6 +56,7 @@
import com.google.gerrit.server.account.InternalAccountDirectory;
import com.google.gerrit.server.api.GerritApiModule;
import com.google.gerrit.server.api.PluginApiModule;
+import com.google.gerrit.server.audit.AuditModule;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.change.ChangeCleanupRunner;
@@ -422,6 +423,7 @@
modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
modules.add(new GerritApiModule());
modules.add(new PluginApiModule());
+ modules.add(new AuditModule());
modules.add(new SearchingChangeCacheImpl.Module(slave));
modules.add(new InternalAccountDirectory.Module());
diff --git a/java/com/google/gerrit/reviewdb/client/Project.java b/java/com/google/gerrit/reviewdb/client/Project.java
index 921667e..996f1ec 100644
--- a/java/com/google/gerrit/reviewdb/client/Project.java
+++ b/java/com/google/gerrit/reviewdb/client/Project.java
@@ -99,6 +99,8 @@
protected String themeName;
+ protected String configRefState;
+
protected Project() {}
public Project(Project.NameKey nameKey) {
@@ -239,4 +241,14 @@
public void setParentName(NameKey n) {
parent = n;
}
+
+ /** Returns the {@code ObjectId} as 40 digit hex of {@code refs/meta/config}'s HEAD. */
+ public String getConfigRefState() {
+ return configRefState;
+ }
+
+ /** Sets the {@code ObjectId} as 40 digit hex of {@code refs/meta/config}'s HEAD. */
+ public void setConfigRefState(String state) {
+ configRefState = state;
+ }
}
diff --git a/java/com/google/gerrit/server/BUILD b/java/com/google/gerrit/server/BUILD
index a67cccb..e99c686 100644
--- a/java/com/google/gerrit/server/BUILD
+++ b/java/com/google/gerrit/server/BUILD
@@ -41,6 +41,7 @@
"//java/com/google/gerrit/prettify:server",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/server/util/git",
"//java/com/google/gerrit/util/cli",
"//java/com/google/gerrit/util/ssl",
"//java/org/apache/commons/net",
diff --git a/java/com/google/gerrit/server/audit/AuditModule.java b/java/com/google/gerrit/server/audit/AuditModule.java
index 0052aaa..df037b6 100644
--- a/java/com/google/gerrit/server/audit/AuditModule.java
+++ b/java/com/google/gerrit/server/audit/AuditModule.java
@@ -16,6 +16,7 @@
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.audit.group.GroupAuditListener;
+import com.google.gerrit.server.group.GroupAuditService;
import com.google.inject.AbstractModule;
public class AuditModule extends AbstractModule {
@@ -24,6 +25,6 @@
protected void configure() {
DynamicSet.setOf(binder(), AuditListener.class);
DynamicSet.setOf(binder(), GroupAuditListener.class);
- bind(AuditService.class);
+ bind(GroupAuditService.class).to(AuditService.class);
}
}
diff --git a/java/com/google/gerrit/server/audit/AuditService.java b/java/com/google/gerrit/server/audit/AuditService.java
index 9528670..2055e33 100644
--- a/java/com/google/gerrit/server/audit/AuditService.java
+++ b/java/com/google/gerrit/server/audit/AuditService.java
@@ -22,12 +22,13 @@
import com.google.gerrit.server.audit.group.GroupAuditListener;
import com.google.gerrit.server.audit.group.GroupMemberAuditEvent;
import com.google.gerrit.server.audit.group.GroupSubgroupAuditEvent;
+import com.google.gerrit.server.group.GroupAuditService;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@Singleton
-public class AuditService {
+public class AuditService implements GroupAuditService {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final DynamicSet<AuditListener> auditListeners;
@@ -47,6 +48,7 @@
}
}
+ @Override
public void dispatchAddMembers(
Account.Id actor,
AccountGroup.UUID updatedGroup,
@@ -63,6 +65,7 @@
}
}
+ @Override
public void dispatchDeleteMembers(
Account.Id actor,
AccountGroup.UUID updatedGroup,
@@ -79,6 +82,7 @@
}
}
+ @Override
public void dispatchAddSubgroups(
Account.Id actor,
AccountGroup.UUID updatedGroup,
@@ -95,6 +99,7 @@
}
}
+ @Override
public void dispatchDeleteSubgroups(
Account.Id actor,
AccountGroup.UUID updatedGroup,
diff --git a/java/com/google/gerrit/server/audit/BUILD b/java/com/google/gerrit/server/audit/BUILD
new file mode 100644
index 0000000..5efdc5a
--- /dev/null
+++ b/java/com/google/gerrit/server/audit/BUILD
@@ -0,0 +1,73 @@
+java_library(
+ name = "audit",
+ srcs = glob(
+ ["**/*.java"],
+ ),
+ resource_strip_prefix = "resources",
+ resources = ["//resources/com/google/gerrit/server"],
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/com/google/gerrit/common:annotations",
+ "//java/com/google/gerrit/common:server",
+ "//java/com/google/gerrit/extensions:api",
+ "//java/com/google/gerrit/index",
+ "//java/com/google/gerrit/index:query_exception",
+ "//java/com/google/gerrit/index/project",
+ "//java/com/google/gerrit/lifecycle",
+ "//java/com/google/gerrit/metrics",
+ "//java/com/google/gerrit/prettify:server",
+ "//java/com/google/gerrit/reviewdb:server",
+ "//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/util/cli",
+ "//java/com/google/gerrit/util/ssl",
+ "//java/org/apache/commons/net",
+ "//java/org/eclipse/jgit:server",
+ "//lib:args4j",
+ "//lib:automaton",
+ "//lib:blame-cache",
+ "//lib:grappa",
+ "//lib:gson",
+ "//lib:guava",
+ "//lib:guava-retrying",
+ "//lib:gwtjsonrpc",
+ "//lib:gwtorm",
+ "//lib:jsch",
+ "//lib:juniversalchardet",
+ "//lib:mime-util",
+ "//lib:pegdown",
+ "//lib:protobuf",
+ "//lib:servlet-api-3_1",
+ "//lib:soy",
+ "//lib:tukaani-xz",
+ "//lib/auto:auto-value",
+ "//lib/auto:auto-value-annotations",
+ "//lib/bouncycastle:bcpkix-neverlink",
+ "//lib/bouncycastle:bcprov-neverlink",
+ "//lib/commons:codec",
+ "//lib/commons:compress",
+ "//lib/commons:dbcp",
+ "//lib/commons:lang",
+ "//lib/commons:net",
+ "//lib/commons:validator",
+ "//lib/flogger:api",
+ "//lib/guice",
+ "//lib/guice:guice-assistedinject",
+ "//lib/guice:guice-servlet",
+ "//lib/jgit/org.eclipse.jgit.archive:jgit-archive",
+ "//lib/jgit/org.eclipse.jgit:jgit",
+ "//lib/jsoup",
+ "//lib/log:jsonevent-layout",
+ "//lib/log:log4j",
+ "//lib/lucene:lucene-analyzers-common",
+ "//lib/lucene:lucene-core-and-backward-codecs",
+ "//lib/lucene:lucene-queryparser",
+ "//lib/mime4j:core",
+ "//lib/mime4j:dom",
+ "//lib/ow2:ow2-asm",
+ "//lib/ow2:ow2-asm-tree",
+ "//lib/ow2:ow2-asm-util",
+ "//lib/prolog:runtime",
+ "//proto:cache_java_proto",
+ ],
+)
diff --git a/java/com/google/gerrit/server/config/GerritGlobalModule.java b/java/com/google/gerrit/server/config/GerritGlobalModule.java
index 57255a3..b6a257b 100644
--- a/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -91,7 +91,6 @@
import com.google.gerrit.server.account.GroupIncludeCacheImpl;
import com.google.gerrit.server.account.VersionedAuthorizedKeys;
import com.google.gerrit.server.account.externalids.ExternalIdModule;
-import com.google.gerrit.server.audit.AuditModule;
import com.google.gerrit.server.auth.AuthBackend;
import com.google.gerrit.server.auth.UniversalAuthBackend;
import com.google.gerrit.server.auth.oauth.OAuthTokenCache;
@@ -301,7 +300,6 @@
bind(IdentifiedUser.GenericFactory.class).in(SINGLETON);
bind(AccountControl.Factory.class);
- install(new AuditModule());
bind(UiActions.class);
bind(GitReferenceUpdated.class);
diff --git a/java/com/google/gerrit/server/group/GroupAuditService.java b/java/com/google/gerrit/server/group/GroupAuditService.java
new file mode 100644
index 0000000..c543a6e
--- /dev/null
+++ b/java/com/google/gerrit/server/group/GroupAuditService.java
@@ -0,0 +1,48 @@
+// 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.server.group;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.reviewdb.client.Account;
+import com.google.gerrit.reviewdb.client.Account.Id;
+import com.google.gerrit.reviewdb.client.AccountGroup;
+import java.sql.Timestamp;
+
+public interface GroupAuditService {
+
+ void dispatchAddMembers(
+ Account.Id actor,
+ AccountGroup.UUID updatedGroup,
+ ImmutableSet<Id> addedMembers,
+ Timestamp addedOn);
+
+ void dispatchDeleteMembers(
+ Account.Id actor,
+ AccountGroup.UUID updatedGroup,
+ ImmutableSet<Account.Id> deletedMembers,
+ Timestamp deletedOn);
+
+ void dispatchAddSubgroups(
+ Account.Id actor,
+ AccountGroup.UUID updatedGroup,
+ ImmutableSet<AccountGroup.UUID> addedSubgroups,
+ Timestamp addedOn);
+
+ void dispatchDeleteSubgroups(
+ Account.Id actor,
+ AccountGroup.UUID updatedGroup,
+ ImmutableSet<AccountGroup.UUID> deletedSubgroups,
+ Timestamp deletedOn);
+}
diff --git a/java/com/google/gerrit/server/group/db/GroupsUpdate.java b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
index 38db2e6..cd38c6a 100644
--- a/java/com/google/gerrit/server/group/db/GroupsUpdate.java
+++ b/java/com/google/gerrit/server/group/db/GroupsUpdate.java
@@ -31,13 +31,13 @@
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.account.GroupIncludeCache;
-import com.google.gerrit.server.audit.AuditService;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.config.GerritServerId;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LockFailureException;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.group.GroupAuditService;
import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.index.group.GroupIndexer;
import com.google.gerrit.server.update.RefUpdateUtil;
@@ -89,7 +89,7 @@
private final GroupCache groupCache;
private final GroupIncludeCache groupIncludeCache;
private final Provider<GroupIndexer> indexer;
- private final AuditService auditService;
+ private final GroupAuditService groupAuditService;
private final RenameGroupOp.Factory renameGroupOpFactory;
@Nullable private final IdentifiedUser currentUser;
private final AuditLogFormatter auditLogFormatter;
@@ -106,7 +106,7 @@
GroupCache groupCache,
GroupIncludeCache groupIncludeCache,
Provider<GroupIndexer> indexer,
- AuditService auditService,
+ GroupAuditService auditService,
AccountCache accountCache,
RenameGroupOp.Factory renameGroupOpFactory,
@GerritServerId String serverId,
@@ -120,7 +120,7 @@
this.groupCache = groupCache;
this.groupIncludeCache = groupIncludeCache;
this.indexer = indexer;
- this.auditService = auditService;
+ this.groupAuditService = auditService;
this.renameGroupOpFactory = renameGroupOpFactory;
this.gitRefUpdated = gitRefUpdated;
this.retryHelper = retryHelper;
@@ -384,14 +384,14 @@
}
if (!createdGroup.getMembers().isEmpty()) {
- auditService.dispatchAddMembers(
+ groupAuditService.dispatchAddMembers(
currentUser.getAccountId(),
createdGroup.getGroupUUID(),
createdGroup.getMembers(),
createdGroup.getCreatedOn());
}
if (!createdGroup.getSubgroups().isEmpty()) {
- auditService.dispatchAddSubgroups(
+ groupAuditService.dispatchAddSubgroups(
currentUser.getAccountId(),
createdGroup.getGroupUUID(),
createdGroup.getSubgroups(),
@@ -405,19 +405,19 @@
}
if (!result.getAddedMembers().isEmpty()) {
- auditService.dispatchAddMembers(
+ groupAuditService.dispatchAddMembers(
currentUser.getAccountId(), result.getGroupUuid(), result.getAddedMembers(), updatedOn);
}
if (!result.getDeletedMembers().isEmpty()) {
- auditService.dispatchDeleteMembers(
+ groupAuditService.dispatchDeleteMembers(
currentUser.getAccountId(), result.getGroupUuid(), result.getDeletedMembers(), updatedOn);
}
if (!result.getAddedSubgroups().isEmpty()) {
- auditService.dispatchAddSubgroups(
+ groupAuditService.dispatchAddSubgroups(
currentUser.getAccountId(), result.getGroupUuid(), result.getAddedSubgroups(), updatedOn);
}
if (!result.getDeletedSubgroups().isEmpty()) {
- auditService.dispatchDeleteSubgroups(
+ groupAuditService.dispatchDeleteSubgroups(
currentUser.getAccountId(),
result.getGroupUuid(),
result.getDeletedSubgroups(),
diff --git a/java/com/google/gerrit/server/index/account/AccountField.java b/java/com/google/gerrit/server/index/account/AccountField.java
index 31e2ada..111991c 100644
--- a/java/com/google/gerrit/server/index/account/AccountField.java
+++ b/java/com/google/gerrit/server/index/account/AccountField.java
@@ -27,11 +27,11 @@
import com.google.common.collect.Iterables;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.index.FieldDef;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.index.SchemaUtil;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.index.RefState;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
diff --git a/java/com/google/gerrit/server/index/account/StalenessChecker.java b/java/com/google/gerrit/server/index/account/StalenessChecker.java
index 6403d3d..0c3e329 100644
--- a/java/com/google/gerrit/server/index/account/StalenessChecker.java
+++ b/java/com/google/gerrit/server/index/account/StalenessChecker.java
@@ -24,6 +24,7 @@
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.index.query.FieldBundle;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
@@ -33,7 +34,6 @@
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.index.IndexUtils;
-import com.google.gerrit.server.index.RefState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
diff --git a/java/com/google/gerrit/server/index/change/ChangeField.java b/java/com/google/gerrit/server/index/change/ChangeField.java
index 3375ce7..5d12e79 100644
--- a/java/com/google/gerrit/server/index/change/ChangeField.java
+++ b/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -43,6 +43,7 @@
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.data.SubmitRequirement;
import com.google.gerrit.index.FieldDef;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.index.SchemaUtil;
import com.google.gerrit.mail.Address;
import com.google.gerrit.reviewdb.client.Account;
@@ -57,7 +58,6 @@
import com.google.gerrit.server.ReviewerSet;
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.index.RefState;
import com.google.gerrit.server.index.change.StalenessChecker.RefStatePattern;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
diff --git a/java/com/google/gerrit/server/index/change/StalenessChecker.java b/java/com/google/gerrit/server/index/change/StalenessChecker.java
index 642385c..0508b60 100644
--- a/java/com/google/gerrit/server/index/change/StalenessChecker.java
+++ b/java/com/google/gerrit/server/index/change/StalenessChecker.java
@@ -31,12 +31,12 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.index.IndexConfig;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.UsedAt;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.index.RefState;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.NoteDbChangeState.PrimaryStorage;
import com.google.gerrit.server.query.change.ChangeData;
diff --git a/java/com/google/gerrit/server/index/project/StalenessChecker.java b/java/com/google/gerrit/server/index/project/StalenessChecker.java
new file mode 100644
index 0000000..5603f08
--- /dev/null
+++ b/java/com/google/gerrit/server/index/project/StalenessChecker.java
@@ -0,0 +1,81 @@
+// 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.server.index.project;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.MultimapBuilder;
+import com.google.common.collect.SetMultimap;
+import com.google.gerrit.index.IndexConfig;
+import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.RefState;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectField;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.query.FieldBundle;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
+import com.google.gerrit.server.project.ProjectCache;
+import java.io.IOException;
+import java.util.Optional;
+import javax.inject.Inject;
+
+public class StalenessChecker {
+ private static final ImmutableSet<String> FIELDS =
+ ImmutableSet.of(ProjectField.NAME.getName(), ProjectField.REF_STATE.getName());
+
+ private final ProjectCache projectCache;
+ private final ProjectIndexCollection indexes;
+ private final IndexConfig indexConfig;
+
+ @Inject
+ StalenessChecker(
+ ProjectCache projectCache, ProjectIndexCollection indexes, IndexConfig indexConfig) {
+ this.projectCache = projectCache;
+ this.indexes = indexes;
+ this.indexConfig = indexConfig;
+ }
+
+ public boolean isStale(Project.NameKey project) throws IOException {
+ ProjectData projectData = projectCache.get(project).toProjectData();
+ ProjectIndex i = indexes.getSearchIndex();
+ if (i == null) {
+ return false; // No index; caller couldn't do anything if it is stale.
+ }
+
+ Optional<FieldBundle> result =
+ i.getRaw(project, QueryOptions.create(indexConfig, 0, 1, FIELDS));
+ if (!result.isPresent()) {
+ return true;
+ }
+
+ SetMultimap<Project.NameKey, RefState> indexedRefStates =
+ RefState.parseStates(result.get().getValue(ProjectField.REF_STATE));
+
+ SetMultimap<Project.NameKey, RefState> currentRefStates =
+ MultimapBuilder.hashKeys().hashSetValues().build();
+ projectData
+ .tree()
+ .stream()
+ .filter(p -> p.getProject().getConfigRefState() != null)
+ .forEach(
+ p ->
+ currentRefStates.put(
+ p.getProject().getNameKey(),
+ RefState.create(RefNames.REFS_CONFIG, p.getProject().getConfigRefState())));
+
+ return !currentRefStates.equals(indexedRefStates);
+ }
+}
diff --git a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
index bf68026..136b4ae 100644
--- a/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
+++ b/java/com/google/gerrit/server/permissions/DefaultPermissionBackend.java
@@ -33,7 +33,6 @@
import com.google.gerrit.server.PeerDaemonUser;
import com.google.gerrit.server.account.CapabilityCollection;
import com.google.gerrit.server.cache.PerThreadCache;
-import com.google.gerrit.server.permissions.PermissionBackendCondition.WithUser;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
diff --git a/java/com/google/gerrit/server/project/ProjectConfig.java b/java/com/google/gerrit/server/project/ProjectConfig.java
index 44aa83b..e3638b6 100644
--- a/java/com/google/gerrit/server/project/ProjectConfig.java
+++ b/java/com/google/gerrit/server/project/ProjectConfig.java
@@ -499,6 +499,9 @@
if (p.getDescription() == null) {
p.setDescription("");
}
+ if (revision != null) {
+ p.setConfigRefState(revision.toObjectId().name());
+ }
if (rc.getStringList(ACCESS, null, KEY_INHERIT_FROM).length > 1) {
// The config must not contain more than one parent to inherit from
diff --git a/java/com/google/gerrit/server/project/ProjectState.java b/java/com/google/gerrit/server/project/ProjectState.java
index 87dbcfc..e36ca4f 100644
--- a/java/com/google/gerrit/server/project/ProjectState.java
+++ b/java/com/google/gerrit/server/project/ProjectState.java
@@ -62,6 +62,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Ref;
@@ -538,7 +539,11 @@
}
public ProjectData toProjectData() {
- return new ProjectData(getProject(), parents().transform(s -> s.getProject().getNameKey()));
+ ProjectData project = null;
+ for (ProjectState state : treeInOrder()) {
+ project = new ProjectData(state.getProject(), Optional.ofNullable(project));
+ }
+ return project;
}
private String readFile(Path p) throws IOException {
diff --git a/java/com/google/gerrit/server/query/project/ProjectPredicates.java b/java/com/google/gerrit/server/query/project/ProjectPredicates.java
index b4f56d4..2e406aa 100644
--- a/java/com/google/gerrit/server/query/project/ProjectPredicates.java
+++ b/java/com/google/gerrit/server/query/project/ProjectPredicates.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.query.project;
+import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.index.project.ProjectData;
import com.google.gerrit.index.project.ProjectField;
import com.google.gerrit.index.project.ProjectPredicate;
@@ -34,5 +35,9 @@
return new ProjectPredicate(ProjectField.DESCRIPTION, description);
}
+ public static Predicate<ProjectData> state(ProjectState state) {
+ return new ProjectPredicate(ProjectField.STATE, state.name());
+ }
+
private ProjectPredicates() {}
}
diff --git a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
index be7ea22..872d3e0 100644
--- a/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/project/ProjectQueryBuilder.java
@@ -17,6 +17,7 @@
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
+import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.index.project.ProjectData;
import com.google.gerrit.index.query.LimitPredicate;
import com.google.gerrit.index.query.Predicate;
@@ -60,6 +61,23 @@
return ProjectPredicates.description(description);
}
+ @Operator
+ public Predicate<ProjectData> state(String state) throws QueryParseException {
+ if (Strings.isNullOrEmpty(state)) {
+ throw error("state operator requires a value");
+ }
+ ProjectState parsedState;
+ try {
+ parsedState = ProjectState.valueOf(state.replace('-', '_').toUpperCase());
+ } catch (IllegalArgumentException e) {
+ throw error("state operator must be either 'active' or 'read-only'");
+ }
+ if (parsedState == ProjectState.HIDDEN) {
+ throw error("state operator must be either 'active' or 'read-only'");
+ }
+ return ProjectPredicates.state(parsedState);
+ }
+
@Override
protected Predicate<ProjectData> defaultField(String query) throws QueryParseException {
// Adapt the capacity of this list when adding more default predicates.
diff --git a/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java b/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
index a8d14f6..40201a8 100644
--- a/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/GetDiffPreferences.java
@@ -50,7 +50,7 @@
@Override
public DiffPreferencesInfo apply(AccountResource rsrc)
throws RestApiException, ConfigInvalidException, IOException, PermissionBackendException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
}
diff --git a/java/com/google/gerrit/server/restapi/account/GetEmails.java b/java/com/google/gerrit/server/restapi/account/GetEmails.java
index 63d042c..85262ee 100644
--- a/java/com/google/gerrit/server/restapi/account/GetEmails.java
+++ b/java/com/google/gerrit/server/restapi/account/GetEmails.java
@@ -44,7 +44,7 @@
@Override
public List<EmailInfo> apply(AccountResource rsrc)
throws AuthException, PermissionBackendException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
}
diff --git a/java/com/google/gerrit/server/restapi/account/PutPreferred.java b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
index 51d28ed..a828987 100644
--- a/java/com/google/gerrit/server/restapi/account/PutPreferred.java
+++ b/java/com/google/gerrit/server/restapi/account/PutPreferred.java
@@ -71,7 +71,7 @@
public Response<String> apply(AccountResource.Email rsrc, Input input)
throws RestApiException, OrmException, IOException, PermissionBackendException,
ConfigInvalidException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
}
return apply(rsrc.getUser(), rsrc.getEmail());
diff --git a/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java b/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
index 6aa88de..f4fa354 100644
--- a/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetDiffPreferences.java
@@ -57,7 +57,7 @@
public DiffPreferencesInfo apply(AccountResource rsrc, DiffPreferencesInfo input)
throws RestApiException, ConfigInvalidException, RepositoryNotFoundException, IOException,
PermissionBackendException, OrmException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
}
diff --git a/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java b/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
index dad6e0f..4e3f1d5 100644
--- a/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetEditPreferences.java
@@ -58,7 +58,7 @@
public EditPreferencesInfo apply(AccountResource rsrc, EditPreferencesInfo input)
throws RestApiException, RepositoryNotFoundException, IOException, ConfigInvalidException,
PermissionBackendException, OrmException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
}
diff --git a/java/com/google/gerrit/server/restapi/account/SetPreferences.java b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
index 11ecfdb..fccdabe 100644
--- a/java/com/google/gerrit/server/restapi/account/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
@@ -63,7 +63,7 @@
public GeneralPreferencesInfo apply(AccountResource rsrc, GeneralPreferencesInfo input)
throws RestApiException, IOException, ConfigInvalidException, PermissionBackendException,
OrmException {
- if (self.get() != rsrc.getUser()) {
+ if (!self.get().hasSameAccountId(rsrc.getUser())) {
permissionBackend.currentUser().check(GlobalPermission.MODIFY_ACCOUNT);
}
diff --git a/java/com/google/gerrit/server/submit/GitModules.java b/java/com/google/gerrit/server/submit/GitModules.java
index 00ce7b2..bf56fd5 100644
--- a/java/com/google/gerrit/server/submit/GitModules.java
+++ b/java/com/google/gerrit/server/submit/GitModules.java
@@ -23,7 +23,7 @@
import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo;
import com.google.gerrit.server.util.RequestId;
-import com.google.gerrit.server.util.SubmoduleSectionParser;
+import com.google.gerrit.server.util.git.SubmoduleSectionParser;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
diff --git a/java/com/google/gerrit/server/util/git/BUILD b/java/com/google/gerrit/server/util/git/BUILD
new file mode 100644
index 0000000..81ca9cd
--- /dev/null
+++ b/java/com/google/gerrit/server/util/git/BUILD
@@ -0,0 +1,9 @@
+java_library(
+ name = "git",
+ srcs = glob(["**/*.java"]),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/com/google/gerrit/reviewdb:server",
+ "//lib/jgit/org.eclipse.jgit:jgit",
+ ],
+)
diff --git a/java/com/google/gerrit/server/util/SubmoduleSectionParser.java b/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
similarity index 97%
rename from java/com/google/gerrit/server/util/SubmoduleSectionParser.java
rename to java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
index 6de2fef..a92b7fd 100644
--- a/java/com/google/gerrit/server/util/SubmoduleSectionParser.java
+++ b/java/com/google/gerrit/server/util/git/SubmoduleSectionParser.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2011 The Android Open Source Project
+// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.server.util;
+package com.google.gerrit.server.util.git;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
diff --git a/java/com/google/gerrit/sshd/BUILD b/java/com/google/gerrit/sshd/BUILD
index 6c810a3..4743b35 100644
--- a/java/com/google/gerrit/sshd/BUILD
+++ b/java/com/google/gerrit/sshd/BUILD
@@ -11,6 +11,7 @@
"//java/com/google/gerrit/metrics",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
+ "//java/com/google/gerrit/server/audit",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/git/receive",
"//java/com/google/gerrit/server/ioutil",
diff --git a/java/com/google/gerrit/testing/BUILD b/java/com/google/gerrit/testing/BUILD
index 55565ad..cf65908 100644
--- a/java/com/google/gerrit/testing/BUILD
+++ b/java/com/google/gerrit/testing/BUILD
@@ -26,6 +26,7 @@
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server:module",
"//java/com/google/gerrit/server/api",
+ "//java/com/google/gerrit/server/audit",
"//java/com/google/gerrit/server/cache/h2",
"//java/com/google/gerrit/server/cache/mem",
"//java/com/google/gerrit/server/restapi",
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index b3f6222..8f9aa14 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -35,6 +35,7 @@
import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.api.GerritApiModule;
import com.google.gerrit.server.api.PluginApiModule;
+import com.google.gerrit.server.audit.AuditModule;
import com.google.gerrit.server.cache.h2.H2CacheModule;
import com.google.gerrit.server.cache.mem.DefaultMemoryCacheModule;
import com.google.gerrit.server.config.AllProjectsName;
@@ -178,6 +179,7 @@
install(new DefaultPermissionBackendModule());
install(new SearchingChangeCacheImpl.Module());
factory(GarbageCollection.Factory.class);
+ install(new AuditModule());
bindScope(RequestScoped.class, PerThreadRequestScope.REQUEST);
diff --git a/javatests/com/google/gerrit/acceptance/api/project/BUILD b/javatests/com/google/gerrit/acceptance/api/project/BUILD
index 768c20b..97c6f33 100644
--- a/javatests/com/google/gerrit/acceptance/api/project/BUILD
+++ b/javatests/com/google/gerrit/acceptance/api/project/BUILD
@@ -4,4 +4,5 @@
srcs = glob(["*IT.java"]),
group = "api_project",
labels = ["api"],
+ deps = ["//java/com/google/gerrit/index/project"],
)
diff --git a/javatests/com/google/gerrit/acceptance/api/project/ProjectIndexerIT.java b/javatests/com/google/gerrit/acceptance/api/project/ProjectIndexerIT.java
new file mode 100644
index 0000000..6fde012
--- /dev/null
+++ b/javatests/com/google/gerrit/acceptance/api/project/ProjectIndexerIT.java
@@ -0,0 +1,129 @@
+// 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.api.project;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.acceptance.GitUtil.fetch;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.gerrit.acceptance.AbstractDaemonTest;
+import com.google.gerrit.index.IndexConfig;
+import com.google.gerrit.index.QueryOptions;
+import com.google.gerrit.index.RefState;
+import com.google.gerrit.index.project.ProjectField;
+import com.google.gerrit.index.project.ProjectIndex;
+import com.google.gerrit.index.project.ProjectIndexCollection;
+import com.google.gerrit.index.project.ProjectIndexer;
+import com.google.gerrit.index.query.FieldBundle;
+import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.index.project.StalenessChecker;
+import com.google.gerrit.server.project.ProjectConfig;
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Consumer;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Ref;
+import org.junit.Test;
+
+public class ProjectIndexerIT extends AbstractDaemonTest {
+ @Inject private ProjectIndexer projectIndexer;
+ @Inject private ProjectIndexCollection indexes;
+ @Inject private IndexConfig indexConfig;
+ @Inject private StalenessChecker stalenessChecker;
+
+ private static final ImmutableSet<String> FIELDS =
+ ImmutableSet.of(ProjectField.NAME.getName(), ProjectField.REF_STATE.getName());
+
+ @Test
+ public void indexProject_indexesRefStateOfProjectAndParents() throws Exception {
+ projectIndexer.index(project);
+ ProjectIndex i = indexes.getSearchIndex();
+ assertThat(i.getSchema().hasField(ProjectField.REF_STATE)).isTrue();
+
+ Optional<FieldBundle> result =
+ i.getRaw(project, QueryOptions.create(indexConfig, 0, 1, FIELDS));
+
+ assertThat(result.isPresent()).isTrue();
+ Iterable<byte[]> refState = result.get().getValue(ProjectField.REF_STATE);
+ assertThat(refState).isNotEmpty();
+
+ Map<Project.NameKey, Collection<RefState>> states = RefState.parseStates(refState).asMap();
+
+ fetch(testRepo, "refs/meta/config:refs/meta/config");
+ Ref projectConfigRef = testRepo.getRepository().exactRef("refs/meta/config");
+ TestRepository<InMemoryRepository> allProjectsRepo = cloneProject(allProjects, admin);
+ fetch(allProjectsRepo, "refs/meta/config:refs/meta/config");
+ Ref allProjectConfigRef = allProjectsRepo.getRepository().exactRef("refs/meta/config");
+ assertThat(states)
+ .containsExactly(
+ project,
+ ImmutableSet.of(RefState.of(projectConfigRef)),
+ allProjects,
+ ImmutableSet.of(RefState.of(allProjectConfigRef)));
+ }
+
+ @Test
+ public void stalenessChecker_currentProject_notStale() throws Exception {
+ assertThat(stalenessChecker.isStale(project)).isFalse();
+ }
+
+ @Test
+ public void stalenessChecker_currentProjectUpdates_isStale() throws Exception {
+ updateProjectConfigWithoutIndexUpdate(project);
+ assertThat(stalenessChecker.isStale(project)).isTrue();
+ }
+
+ @Test
+ public void stalenessChecker_parentProjectUpdates_isStale() throws Exception {
+ updateProjectConfigWithoutIndexUpdate(allProjects);
+ assertThat(stalenessChecker.isStale(project)).isTrue();
+ }
+
+ @Test
+ public void stalenessChecker_hierarchyChange_isStale() throws Exception {
+ Project.NameKey p1 = createProject("p1", allProjects);
+ Project.NameKey p2 = createProject("p2", allProjects);
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ u.getConfig().getProject().setParentName(p1);
+ u.save();
+ }
+ assertThat(stalenessChecker.isStale(project)).isFalse();
+
+ updateProjectConfigWithoutIndexUpdate(p1, c -> c.getProject().setParentName(p2));
+ assertThat(stalenessChecker.isStale(project)).isTrue();
+ }
+
+ private void updateProjectConfigWithoutIndexUpdate(Project.NameKey project) throws Exception {
+ updateProjectConfigWithoutIndexUpdate(
+ project, c -> c.getProject().setDescription("making it stale"));
+ }
+
+ private void updateProjectConfigWithoutIndexUpdate(
+ Project.NameKey project, Consumer<ProjectConfig> update) throws Exception {
+ try (AutoCloseable ignored = disableProjectIndex()) {
+ try (ProjectConfigUpdate u = updateProject(project)) {
+ update.accept(u.getConfig());
+ u.save();
+ }
+ } catch (UnsupportedOperationException e) {
+ // Drop, as we just wanted to drop the index update
+ return;
+ }
+ fail("should have a UnsupportedOperationException");
+ }
+}
diff --git a/javatests/com/google/gerrit/common/data/GroupReferenceTest.java b/javatests/com/google/gerrit/common/data/GroupReferenceTest.java
index 4181423..717e122 100644
--- a/javatests/com/google/gerrit/common/data/GroupReferenceTest.java
+++ b/javatests/com/google/gerrit/common/data/GroupReferenceTest.java
@@ -18,9 +18,13 @@
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroup.UUID;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
public class GroupReferenceTest {
+ @Rule public ExpectedException exception = ExpectedException.none();
+
@Test
public void forGroupDescription() {
String name = "foo";
@@ -54,6 +58,31 @@
}
@Test
+ public void create() {
+ AccountGroup.UUID uuid = new AccountGroup.UUID("uuid");
+ String name = "foo";
+ GroupReference groupReference = new GroupReference(uuid, name);
+ assertThat(groupReference.getUUID()).isEqualTo(uuid);
+ assertThat(groupReference.getName()).isEqualTo(name);
+ }
+
+ @Test
+ public void createWithoutUuid() {
+ // GroupReferences where the UUID is null are used to represent groups from project.config that
+ // cannot be resolved.
+ String name = "foo";
+ GroupReference groupReference = new GroupReference(null, name);
+ assertThat(groupReference.getUUID()).isNull();
+ assertThat(groupReference.getName()).isEqualTo(name);
+ }
+
+ @Test
+ public void cannotCreateWithoutName() {
+ exception.expect(NullPointerException.class);
+ new GroupReference(new AccountGroup.UUID("uuid"), null);
+ }
+
+ @Test
public void isGroupReference() {
assertThat(GroupReference.isGroupReference("foo")).isFalse();
assertThat(GroupReference.isGroupReference("groupfoo")).isFalse();
@@ -82,6 +111,8 @@
groupReference.setUUID(uuid2);
assertThat(groupReference.getUUID()).isEqualTo(uuid2);
+ // GroupReferences where the UUID is null are used to represent groups from project.config that
+ // cannot be resolved.
groupReference.setUUID(null);
assertThat(groupReference.getUUID()).isNull();
}
@@ -97,8 +128,8 @@
groupReference.setName(name2);
assertThat(groupReference.getName()).isEqualTo(name2);
+ exception.expect(NullPointerException.class);
groupReference.setName(null);
- assertThat(groupReference.getName()).isNull();
}
@Test
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticV5QueryProjectsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticV5QueryProjectsTest.java
index 7b49e1d..98e466e 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticV5QueryProjectsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticV5QueryProjectsTest.java
@@ -67,7 +67,7 @@
Config elasticsearchConfig = new Config(config);
InMemoryModule.setDefaults(elasticsearchConfig);
String indicesPrefix = testName();
- ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix);
+ ElasticTestUtils.configure(elasticsearchConfig, nodeInfo.port, indicesPrefix, "changeme");
return Guice.createInjector(new InMemoryModule(elasticsearchConfig, notesMigration));
}
}
diff --git a/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java b/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
index acb33e9..51bda66 100644
--- a/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
+++ b/javatests/com/google/gerrit/server/index/change/StalenessCheckerTest.java
@@ -24,11 +24,11 @@
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.ListMultimap;
+import com.google.gerrit.index.RefState;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.index.RefState;
import com.google.gerrit.server.index.change.StalenessChecker.RefStatePattern;
import com.google.gerrit.server.notedb.NoteDbChangeState;
import com.google.gerrit.testing.GerritBaseTests;
diff --git a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
index e34746c..2eec006 100644
--- a/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/AbstractQueryProjectsTest.java
@@ -15,15 +15,21 @@
package com.google.gerrit.server.query.project;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.TruthJUnit.assume;
import static java.util.stream.Collectors.toList;
import com.google.common.base.CharMatcher;
import com.google.gerrit.extensions.api.GerritApi;
+import com.google.gerrit.extensions.api.projects.ConfigInput;
import com.google.gerrit.extensions.api.projects.ProjectInput;
import com.google.gerrit.extensions.api.projects.Projects.QueryRequest;
+import com.google.gerrit.extensions.client.ProjectState;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.index.Schema;
+import com.google.gerrit.index.project.ProjectData;
+import com.google.gerrit.index.project.ProjectIndexCollection;
import com.google.gerrit.lifecycle.LifecycleManager;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
@@ -38,7 +44,6 @@
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.query.account.InternalAccountQuery;
import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.ManualRequestContext;
import com.google.gerrit.server.util.OneOffRequestContext;
@@ -83,7 +88,7 @@
@Inject protected OneOffRequestContext oneOffRequestContext;
- @Inject protected InternalAccountQuery internalAccountQuery;
+ @Inject protected ProjectIndexCollection indexes;
@Inject protected AllProjectsName allProjects;
@@ -211,6 +216,30 @@
}
@Test
+ public void byState() throws Exception {
+ assume().that(getSchemaVersion() >= 2).isTrue();
+
+ ProjectInfo project1 = createProjectWithState(name("project1"), ProjectState.ACTIVE);
+ ProjectInfo project2 = createProjectWithState(name("project2"), ProjectState.READ_ONLY);
+ assertQuery("state:active", project1);
+ assertQuery("state:read-only", project2);
+ }
+
+ @Test
+ public void byState_emptyQuery() throws Exception {
+ exception.expect(BadRequestException.class);
+ exception.expectMessage("state operator requires a value");
+ assertQuery("state:\"\"");
+ }
+
+ @Test
+ public void byState_badQuery() throws Exception {
+ exception.expect(BadRequestException.class);
+ exception.expectMessage("state operator must be either 'active' or 'read-only'");
+ assertQuery("state:bla");
+ }
+
+ @Test
public void byDefaultField() throws Exception {
ProjectInfo project1 = createProject(name("foo-project"));
ProjectInfo project2 = createProject(name("project2"));
@@ -291,6 +320,14 @@
return gApi.projects().create(in).get();
}
+ protected ProjectInfo createProjectWithState(String name, ProjectState state) throws Exception {
+ ProjectInfo info = createProject(name);
+ ConfigInput config = new ConfigInput();
+ config.state = state;
+ gApi.projects().name(info.name).config(config);
+ return info;
+ }
+
protected ProjectInfo getProject(Project.NameKey nameKey) throws Exception {
return gApi.projects().name(nameKey.get()).get();
}
@@ -354,6 +391,14 @@
return b.toString();
}
+ protected int getSchemaVersion() {
+ return getSchema().getVersion();
+ }
+
+ protected Schema<ProjectData> getSchema() {
+ return indexes.getSearchIndex().getSchema();
+ }
+
protected static Iterable<String> names(ProjectInfo... projects) {
return names(Arrays.asList(projects));
}
diff --git a/javatests/com/google/gerrit/server/query/project/BUILD b/javatests/com/google/gerrit/server/query/project/BUILD
index eaa3df3..f0c455e 100644
--- a/javatests/com/google/gerrit/server/query/project/BUILD
+++ b/javatests/com/google/gerrit/server/query/project/BUILD
@@ -9,6 +9,8 @@
visibility = ["//visibility:public"],
deps = [
"//java/com/google/gerrit/extensions:api",
+ "//java/com/google/gerrit/index",
+ "//java/com/google/gerrit/index/project",
"//java/com/google/gerrit/lifecycle",
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
diff --git a/javatests/com/google/gerrit/server/util/git/BUILD b/javatests/com/google/gerrit/server/util/git/BUILD
new file mode 100644
index 0000000..928705c
--- /dev/null
+++ b/javatests/com/google/gerrit/server/util/git/BUILD
@@ -0,0 +1,32 @@
+load("//tools/bzl:junit.bzl", "junit_tests")
+
+junit_tests(
+ name = "git_tests",
+ size = "small",
+ srcs = glob(
+ ["**/*.java"],
+ ),
+ visibility = ["//visibility:public"],
+ deps = [
+ "//java/com/google/gerrit/reviewdb:server",
+ "//java/com/google/gerrit/server/util/git",
+ "//java/com/google/gerrit/truth",
+ "//java/org/eclipse/jgit:server",
+ "//lib:grappa",
+ "//lib:gson",
+ "//lib:guava",
+ "//lib:guava-retrying",
+ "//lib:gwtorm",
+ "//lib:protobuf",
+ "//lib/auto:auto-value",
+ "//lib/auto:auto-value-annotations",
+ "//lib/commons:codec",
+ "//lib/guice",
+ "//lib/jgit/org.eclipse.jgit:jgit",
+ "//lib/jgit/org.eclipse.jgit.junit:junit",
+ "//lib/truth",
+ "//lib/truth:truth-java8-extension",
+ "//lib/truth:truth-proto-extension",
+ "//proto:cache_java_proto",
+ ],
+)
diff --git a/javatests/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java b/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
similarity index 91%
rename from javatests/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java
rename to javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
index d0225c7..0ec9b38 100644
--- a/javatests/com/google/gerrit/acceptance/git/SubmoduleSectionParserIT.java
+++ b/javatests/com/google/gerrit/server/util/git/SubmoduleSectionParserTest.java
@@ -12,26 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.acceptance.git;
+package com.google.gerrit.server.util.git;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.Sets;
-import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.SubmoduleSubscription;
-import com.google.gerrit.server.util.SubmoduleSectionParser;
import java.util.Set;
import org.eclipse.jgit.lib.Config;
import org.junit.Test;
-public class SubmoduleSectionParserIT extends AbstractDaemonTest {
+public class SubmoduleSectionParserTest {
private static final String THIS_SERVER = "http://localhost/";
@Test
public void followMasterBranch() throws Exception {
- Project.NameKey p = createProject("a");
+ Project.NameKey p = new Project.NameKey("proj");
Config cfg = new Config();
cfg.fromText(
""
@@ -56,7 +54,7 @@
@Test
public void followMatchingBranch() throws Exception {
- Project.NameKey p = createProject("a");
+ Project.NameKey p = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -92,7 +90,7 @@
@Test
public void followAnotherBranch() throws Exception {
- Project.NameKey p = createProject("a");
+ Project.NameKey p = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -117,7 +115,7 @@
@Test
public void withAnotherURI() throws Exception {
- Project.NameKey p = createProject("a");
+ Project.NameKey p = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -142,7 +140,7 @@
@Test
public void withSlashesInProjectName() throws Exception {
- Project.NameKey p = createProject("project/with/slashes/a");
+ Project.NameKey p = new Project.NameKey("project/with/slashes/a");
Config cfg = new Config();
cfg.fromText(
""
@@ -167,7 +165,7 @@
@Test
public void withSlashesInPath() throws Exception {
- Project.NameKey p = createProject("a");
+ Project.NameKey p = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -192,8 +190,8 @@
@Test
public void withMoreSections() throws Exception {
- Project.NameKey p1 = createProject("a");
- Project.NameKey p2 = createProject("b");
+ Project.NameKey p1 = new Project.NameKey("a");
+ Project.NameKey p2 = new Project.NameKey("b");
Config cfg = new Config();
cfg.fromText(
""
@@ -225,8 +223,8 @@
@Test
public void withSubProjectFound() throws Exception {
- Project.NameKey p1 = createProject("a/b");
- Project.NameKey p2 = createProject("b");
+ Project.NameKey p1 = new Project.NameKey("a/b");
+ Project.NameKey p2 = new Project.NameKey("b");
Config cfg = new Config();
cfg.fromText(
"\n"
@@ -258,10 +256,10 @@
@Test
public void withAnInvalidSection() throws Exception {
- Project.NameKey p1 = createProject("a");
- Project.NameKey p2 = createProject("b");
- Project.NameKey p3 = createProject("d");
- Project.NameKey p4 = createProject("e");
+ Project.NameKey p1 = new Project.NameKey("a");
+ Project.NameKey p2 = new Project.NameKey("b");
+ Project.NameKey p3 = new Project.NameKey("d");
+ Project.NameKey p4 = new Project.NameKey("e");
Config cfg = new Config();
cfg.fromText(
"\n"
@@ -328,7 +326,7 @@
@Test
public void withSectionToOtherServer() throws Exception {
- Project.NameKey p1 = createProject("a");
+ Project.NameKey p1 = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -349,7 +347,7 @@
@Test
public void withRelativeURI() throws Exception {
- Project.NameKey p1 = createProject("a");
+ Project.NameKey p1 = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -374,7 +372,7 @@
@Test
public void withDeepRelativeURI() throws Exception {
- Project.NameKey p1 = createProject("a");
+ Project.NameKey p1 = new Project.NameKey("a");
Config cfg = new Config();
cfg.fromText(
""
@@ -400,7 +398,7 @@
@Test
public void withOverlyDeepRelativeURI() throws Exception {
- Project.NameKey p1 = createProject("nested/a");
+ Project.NameKey p1 = new Project.NameKey("nested/a");
Config cfg = new Config();
cfg.fromText(
""
diff --git a/lib/jgit/jgit.bzl b/lib/jgit/jgit.bzl
index be90acb..384469c 100644
--- a/lib/jgit/jgit.bzl
+++ b/lib/jgit/jgit.bzl
@@ -2,7 +2,7 @@
_JGIT_VERS = "5.0.1.201806211838-r"
-_DOC_VERS = "5.0.0.201806131550-r" # Set to _JGIT_VERS unless using a snapshot
+_DOC_VERS = _JGIT_VERS # Set to _JGIT_VERS unless using a snapshot
JGIT_DOC_URL = "http://download.eclipse.org/jgit/site/" + _DOC_VERS + "/apidocs"
diff --git a/plugins/codemirror-editor b/plugins/codemirror-editor
index 53dccff..318504d 160000
--- a/plugins/codemirror-editor
+++ b/plugins/codemirror-editor
@@ -1 +1 @@
-Subproject commit 53dccff17c029459999ff70ac886b80626af634b
+Subproject commit 318504d0eb74f2f9c2967e9865ace6d5b57638c6
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
index 61df877..45bc5f6 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section.html
@@ -45,7 +45,7 @@
.header,
#deletedContainer {
align-items: center;
- background: #f6f6f6;
+ background: var(--table-header-background-color);
border-bottom: 1px dotted var(--border-color);
display: flex;
justify-content: space-between;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
index 6ea7cf3..7eb2b6c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
@@ -171,11 +171,14 @@
</td>
<td class="cell project"
hidden$="[[isColumnHidden('Project', visibleChangeTableColumns)]]">
- <a class="fullProject" href$="[[_computeProjectURL(change.project)]]">
- [[change.project]]
+ <a class="fullProject" href$="[[_computeProjectURL(change)]]">
+ [[_computeProjectDisplay(change)]]
</a>
- <a class="truncatedProject" href$="[[_computeProjectURL(change.project)]]">
- [[_computeTruncatedProject(change.project)]]
+ <a
+ class="truncatedProject"
+ href$="[[_computeProjectURL(change)]]"
+ title$="[[_computeProjectDisplay(change)]]">
+ [[_computeProjectDisplay(change, 'true')]]
</a>
</td>
<td class="cell branch"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index 259580b..b73a237 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -122,22 +122,36 @@
return '';
},
- _computeProjectURL(project) {
- return Gerrit.Nav.getUrlForProjectChanges(project, true);
+ _computeProjectURL(change) {
+ return Gerrit.Nav.getUrlForProjectChanges(change.project, true,
+ change.internalHost);
},
_computeProjectBranchURL(change) {
- return Gerrit.Nav.getUrlForBranch(change.branch, change.project);
+ return Gerrit.Nav.getUrlForBranch(change.branch, change.project, null,
+ change.internalHost);
},
_computeTopicURL(change) {
if (!change.topic) { return ''; }
- return Gerrit.Nav.getUrlForTopic(change.topic);
+ return Gerrit.Nav.getUrlForTopic(change.topic, change.internalHost);
},
- _computeTruncatedProject(project) {
- if (!project) { return ''; }
- return this.truncatePath(project, 2);
+ /**
+ * Computes the display string for the project column. If there is a host
+ * specified in the change detail, the string will be prefixed with it.
+ *
+ * @param {!Object} change
+ * @param {string=} truncate whether or not the project name should be
+ * truncated. If this value is truthy, the name will be truncated.
+ * @return {string}
+ */
+ _computeProjectDisplay(change, truncate) {
+ if (!change || !change.project) { return ''; }
+ let str = '';
+ if (change.internalHost) { str += change.internalHost + '/'; }
+ str += truncate ? this.truncatePath(change.project, 2) : change.project;
+ return str;
},
_computeAccountStatusString(account) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
index 81e1034..f4c66c7 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_test.html
@@ -37,8 +37,10 @@
<script>
suite('gr-change-list-item tests', () => {
let element;
+ let sandbox;
setup(() => {
+ sandbox = sinon.sandbox.create();
stub('gr-rest-api-interface', {
getConfig() { return Promise.resolve({}); },
getLoggedIn() { return Promise.resolve(false); },
@@ -46,6 +48,8 @@
element = fixture('basic');
});
+ teardown(() => { sandbox.restore(); });
+
test('computed fields', () => {
assert.equal(element._computeLabelClass({labels: {}}),
'cell label u-gray-background');
@@ -249,5 +253,39 @@
deletions: 999,
}), 'XL');
});
+
+ test('change params passed to gr-navigation', () => {
+ sandbox.stub(Gerrit.Nav);
+ const change = {
+ internalHost: 'test-host',
+ project: 'test-repo',
+ topic: 'test-topic',
+ branch: 'test-branch',
+ };
+ element.change = change;
+ flushAsynchronousOperations();
+
+ assert.deepEqual(Gerrit.Nav.getUrlForChange.lastCall.args, [change]);
+ assert.deepEqual(Gerrit.Nav.getUrlForProjectChanges.lastCall.args,
+ [change.project, true, change.internalHost]);
+ assert.deepEqual(Gerrit.Nav.getUrlForBranch.lastCall.args,
+ [change.branch, change.project, null, change.internalHost]);
+ assert.deepEqual(Gerrit.Nav.getUrlForTopic.lastCall.args,
+ [change.topic, change.internalHost]);
+ });
+
+ test('_computeProjectDisplay', () => {
+ const change = {
+ project: 'a/test/repo',
+ internalHost: 'host',
+ };
+ assert.equal(element._computeProjectDisplay(change), 'host/a/test/repo');
+ assert.equal(element._computeProjectDisplay(change, true),
+ 'host/…/test/repo');
+ delete change.internalHost;
+ assert.equal(element._computeProjectDisplay(change), 'a/test/repo');
+ assert.equal(element._computeProjectDisplay(change, true),
+ '…/test/repo');
+ });
});
</script>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
index 3a7ff10..fc00299 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.html
@@ -86,7 +86,8 @@
changes="{{_changes}}"
preferences="[[preferences]]"
selected-index="{{viewState.selectedChangeIndex}}"
- show-star="[[_loggedIn]]"></gr-change-list>
+ show-star="[[_loggedIn]]"
+ on-toggle-star="_handleToggleStar"></gr-change-list>
<nav class$="[[_computeNavClass(_loading)]]">
Page [[_computePage(_offset, _changesPerPage)]]
<a id="prevArrow"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
index 2a05a2f..9b099cd 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
@@ -263,5 +263,10 @@
_computeLoggedIn(account) {
return !!(account && Object.keys(account).length > 0);
},
+
+ _handleToggleStar(e) {
+ this.$.restAPI.saveChangeStarred(e.detail.change._number,
+ e.detail.starred);
+ },
});
})();
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
index 9930bf5..33bc338 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.js
@@ -18,10 +18,9 @@
'use strict';
const NUMBER_FIXED_COLUMNS = 3;
-
const CLOSED_STATUS = ['MERGED', 'ABANDONED'];
-
const LABEL_PREFIX_INVALID_PROLOG = 'Invalid-Prolog-Rules-Label-Name--';
+ const MAX_SHORTCUT_CHARS = 5;
Polymer({
is: 'gr-change-list',
@@ -185,10 +184,12 @@
if (labelName.startsWith(LABEL_PREFIX_INVALID_PROLOG)) {
labelName = labelName.slice(LABEL_PREFIX_INVALID_PROLOG.length);
}
- return labelName.split('-').reduce((a, i) => {
- if (!i) { return a; }
- return a + i[0].toUpperCase();
- }, '');
+ return labelName.split('-')
+ .reduce((a, i) => {
+ if (!i) { return a; }
+ return a + i[0].toUpperCase();
+ }, '')
+ .slice(0, MAX_SHORTCUT_CHARS);
},
_changesChanged(changes) {
@@ -306,10 +307,7 @@
}
const changeEl = changeEls[index];
- const change = changeEl.change;
- const newVal = !change.starred;
- changeEl.set('change.starred', newVal);
- this.$.restAPI.saveChangeStarred(change._number, newVal);
+ changeEl.$$('gr-change-star').toggleStar();
},
_changeForIndex(index) {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
index 9ce5764..39d7ab1 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_test.html
@@ -132,6 +132,8 @@
'Some-Special-Label-7'), 'SSL7');
assert.equal(element._computeLabelShortcut('--Too----many----dashes---'),
'TMD');
+ assert.equal(element._computeLabelShortcut(
+ 'Really-rather-entirely-too-long-of-a-label-name'), 'RRETL');
});
test('colspans', () => {
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 1935962..1b21543 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
@@ -60,7 +60,8 @@
account="[[account]]"
preferences="[[preferences]]"
selected-index="{{viewState.selectedChangeIndex}}"
- sections="[[_results]]"></gr-change-list>
+ sections="[[_results]]"
+ on-toggle-star="_handleToggleStar"></gr-change-list>
</div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
<gr-reporting id="reporting"></gr-reporting>
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 f86c98c..9cf76da 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
@@ -241,5 +241,10 @@
_computeUserHeaderClass(userParam) {
return userParam === 'self' ? 'hide' : '';
},
+
+ _handleToggleStar(e) {
+ this.$.restAPI.saveChangeStarred(e.detail.change._number,
+ e.detail.starred);
+ },
});
})();
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 5a56475..1b911e0 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
@@ -273,6 +273,12 @@
#commitMessageEditor {
min-width: 0;
}
+ .commitMessage {
+ margin-right: 0;
+ }
+ .mainChangeInfo {
+ padding-right: 0;
+ }
}
/* NOTE: If you update this breakpoint, also update the
BREAKPOINT_RELATED_SMALL in the JS */
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 e217b4b..dfe5410 100644
--- a/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
+++ b/polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.html
@@ -177,13 +177,15 @@
* @param {!string} project The name of the project.
* @param {boolean=} opt_openOnly When true, only search open changes in
* the project.
+ * @param {string=} opt_host The host in which to search.
* @return {string}
*/
- getUrlForProjectChanges(project, opt_openOnly) {
+ getUrlForProjectChanges(project, opt_openOnly, opt_host) {
return this._getUrlFor({
view: Gerrit.Nav.View.SEARCH,
project,
statuses: opt_openOnly ? ['open'] : [],
+ host: opt_host,
});
},
@@ -191,26 +193,30 @@
* @param {string} branch The name of the branch.
* @param {string} project The name of the project.
* @param {string=} opt_status The status to search.
+ * @param {string=} opt_host The host in which to search.
* @return {string}
*/
- getUrlForBranch(branch, project, opt_status) {
+ getUrlForBranch(branch, project, opt_status, opt_host) {
return this._getUrlFor({
view: Gerrit.Nav.View.SEARCH,
branch,
project,
statuses: opt_status ? [opt_status] : undefined,
+ host: opt_host,
});
},
/**
* @param {string} topic The name of the topic.
+ * @param {string=} opt_host The host in which to search.
* @return {string}
*/
- getUrlForTopic(topic) {
+ getUrlForTopic(topic, opt_host) {
return this._getUrlFor({
view: Gerrit.Nav.View.SEARCH,
topic,
statuses: ['open', 'merged'],
+ host: opt_host,
});
},
@@ -267,6 +273,7 @@
patchNum: opt_patchNum,
basePatchNum: opt_basePatchNum,
edit: opt_isEdit,
+ host: change.internalHost || undefined,
});
},
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index ea69fc2..edf9f5a 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -457,7 +457,11 @@
this._discardDraft();
return;
}
- this._openOverlay(this.confirmDiscardOverlay);
+
+ this._openOverlay(this.confirmDiscardOverlay).then(() => {
+ this.confirmDiscardOverlay.querySelector('#confirmDiscardDialog')
+ .resetFocus();
+ });
},
_handleConfirmDiscard(e) {
@@ -626,9 +630,7 @@
_openOverlay(overlay) {
Polymer.dom(Gerrit.getRootElement()).appendChild(overlay);
- this.async(() => {
- overlay.open();
- }, 1);
+ return overlay.open();
},
_closeOverlay(overlay) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index b41ab23..f1ac649 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -614,7 +614,8 @@
setup(() => {
discardStub = sandbox.stub(element, '_discardDraft');
- overlayStub = sandbox.stub(element, '_openOverlay');
+ overlayStub = sandbox.stub(element, '_openOverlay')
+ .returns(Promise.resolve());
mockEvent = {preventDefault: sinon.stub()};
});
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
index 70b2635..a14c652 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.html
@@ -17,7 +17,6 @@
<link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../shared/gr-icons/gr-icons.html">
-<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html">
<dom-module id="gr-change-star">
@@ -36,7 +35,6 @@
class$="[[_computeStarClass(change.starred)]]"
icon$="[[_computeStarIcon(change.starred)]]"></iron-icon>
</button>
- <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
</template>
<script src="gr-change-star.js"></script>
</dom-module>
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
index 9646735..3c46d1b 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star.js
@@ -20,14 +20,18 @@
Polymer({
is: 'gr-change-star',
+ /**
+ * Fired when star state is toggled.
+ *
+ * @event toggle-star
+ */
+
properties: {
/** @type {?} */
change: {
type: Object,
notify: true,
},
-
- _xhrPromise: Object, // Used for testing.
},
_computeStarClass(starred) {
@@ -42,8 +46,10 @@
toggleStar() {
const newVal = !this.change.starred;
this.set('change.starred', newVal);
- this._xhrPromise = this.$.restAPI.saveChangeStarred(this.change._number,
- newVal);
+ this.dispatchEvent(new CustomEvent('toggle-star', {
+ bubbles: true,
+ detail: {change: this.change, starred: newVal},
+ }));
},
});
})();
diff --git a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
index f24b45c..0ca9368 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-change-star/gr-change-star_test.html
@@ -37,9 +37,6 @@
let element;
setup(() => {
- stub('gr-rest-api-interface', {
- saveChangeStarred() { return Promise.resolve({ok: true}); },
- });
element = fixture('basic');
element.change = {
_number: 2,
@@ -60,23 +57,21 @@
});
test('starring', done => {
- element.set('change.starred', false);
- MockInteractions.tap(element.$$('button'));
-
- element._xhrPromise.then(req => {
+ element.addEventListener('toggle-star', () => {
assert.equal(element.change.starred, true);
done();
});
+ element.set('change.starred', false);
+ MockInteractions.tap(element.$$('button'));
});
test('unstarring', done => {
- element.set('change.starred', true);
- MockInteractions.tap(element.$$('button'));
-
- element._xhrPromise.then(req => {
+ element.addEventListener('toggle-star', () => {
assert.equal(element.change.starred, false);
done();
});
+ element.set('change.starred', true);
+ MockInteractions.tap(element.$$('button'));
});
});
</script>
diff --git a/polygerrit-ui/externs/BUILD b/polygerrit-ui/externs/BUILD
new file mode 100644
index 0000000..fab3954
--- /dev/null
+++ b/polygerrit-ui/externs/BUILD
@@ -0,0 +1,25 @@
+# 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(
+ default_visibility = ["//visibility:public"],
+)
+
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
+
+closure_js_library(
+ name = "plugin",
+ srcs = ["plugin.js"],
+ no_closure_library = True,
+)
diff --git a/polygerrit-ui/externs/plugin.js b/polygerrit-ui/externs/plugin.js
new file mode 100644
index 0000000..edace7d
--- /dev/null
+++ b/polygerrit-ui/externs/plugin.js
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * 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.
+ */
+
+/**
+ * @fileoverview Closure compiler externs for the Gerrit UI plugins.
+ * @externs
+ */
+
+var Gerrit = {};
+
+/**
+ * @param {!Function} callback
+ */
+Gerrit.install = function(callback) {};
diff --git a/tools/bzl/js.bzl b/tools/bzl/js.bzl
index fbacfad..6590cd6 100644
--- a/tools/bzl/js.bzl
+++ b/tools/bzl/js.bzl
@@ -3,6 +3,7 @@
GERRIT = "GERRIT:"
load("//lib/js:npm.bzl", "NPM_SHA1S", "NPM_VERSIONS")
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_binary", "closure_js_library")
def _npm_tarball(name):
return "%s@%s.npm_binary.tgz" % (name, NPM_VERSIONS[name])
@@ -146,9 +147,9 @@
transitive_versions += d.transitive_versions
return struct(
- transitive_zipfiles = transitive_zipfiles,
- transitive_versions = transitive_versions,
transitive_licenses = transitive_licenses,
+ transitive_versions = transitive_versions,
+ transitive_zipfiles = transitive_zipfiles,
)
_common_attrs = {
@@ -187,9 +188,9 @@
licenses += depset([ctx.file.license])
return struct(
- transitive_zipfiles = list([ctx.outputs.zip]),
- transitive_versions = depset(),
transitive_licenses = licenses,
+ transitive_versions = depset(),
+ transitive_zipfiles = list([ctx.outputs.zip]),
)
js_component = rule(
@@ -271,9 +272,9 @@
)
return struct(
- transitive_zipfiles = zips,
- transitive_versions = versions,
transitive_licenses = licenses,
+ transitive_versions = versions,
+ transitive_zipfiles = zips,
)
bower_component_bundle = rule(
@@ -341,8 +342,8 @@
# from the environment, and it may be under $HOME, so we can't run
# in the sandbox.
node_tweaks = dict(
- use_default_shell_env = True,
execution_requirements = {"local": "1"},
+ use_default_shell_env = True,
)
ctx.actions.run_shell(
mnemonic = "Vulcanize",
@@ -427,6 +428,93 @@
"""Vulcanize runs vulcanize and (optionally) crisper on a set of sources."""
_vulcanize_rule(*args, pkg = PACKAGE_NAME, **kwargs)
-def polygerrit_plugin(*args, **kwargs):
- """Bundles plugin dependencies for deployment."""
- _vulcanize_rule(*args, pkg = PACKAGE_NAME, **kwargs)
+def polygerrit_plugin(name, app, srcs = [], assets = None, **kwargs):
+ """Bundles plugin dependencies for deployment.
+
+ This rule bundles all Polymer elements and JS dependencies into .html and .js files.
+ Run-time dependencies (e.g. JS libraries loaded after plugin starts) should be provided using "assets" property.
+ Output of this rule is a FileSet with "${name}_fs", with deploy artifacts in "plugins/${name}/static".
+
+ Args:
+ name: String, plugin name.
+ app: String, the main or root source file.
+ assets: Fileset, additional files to be used by plugin in runtime, exported to "plugins/${name}/static".
+ srcs: Source files required for combining.
+ """
+
+ # Combines all .js and .html files into foo_combined.js and foo_combined.html
+ _vulcanize_rule(
+ name = name + "_combined",
+ app = app,
+ srcs = srcs if app in srcs else srcs + [app],
+ pkg = PACKAGE_NAME,
+ **kwargs
+ )
+
+ closure_js_binary(
+ name = name + "_bin",
+ compilation_level = "SIMPLE",
+ defs = [
+ "--polymer_version=1",
+ "--language_out=ECMASCRIPT6",
+ "--rewrite_polyfills=false",
+ ],
+ deps = [
+ name + "_closure_lib",
+ ],
+ )
+
+ closure_js_library(
+ name = name + "_closure_lib",
+ srcs = [name + "_combined.js"],
+ convention = "GOOGLE",
+ no_closure_library = True,
+ deps = [
+ "//lib/polymer_externs:polymer_closure",
+ "//polygerrit-ui/externs:plugin",
+ ],
+ )
+
+ native.genrule(
+ name = name + "_rename_html",
+ srcs = [name + "_combined.html"],
+ outs = [name + ".html"],
+ cmd = "sed 's/<script src=\"" + name + "_combined.js\"/<script src=\"" + name + ".js\"/g' $(SRCS) > $(OUTS)",
+ output_to_bindir = True,
+ )
+
+ native.genrule(
+ name = name + "_rename_js",
+ srcs = [name + "_bin.js"],
+ outs = [name + ".js"],
+ cmd = "cp $< $@",
+ output_to_bindir = True,
+ )
+
+ static_files = [
+ name + ".js",
+ name + ".html",
+ ]
+
+ if assets:
+ nested, direct = [], []
+ for x in assets:
+ target = nested if "/" in x else direct
+ target.append(x)
+
+ static_files += direct
+
+ if nested:
+ native.genrule(
+ name = name + "_copy_assets",
+ srcs = assets,
+ outs = [f.split("/")[-1] for f in nested],
+ cmd = "cp $(SRCS) $(@D)",
+ output_to_bindir = True,
+ )
+ static_files += [":" + name + "_copy_assets"]
+
+ native.filegroup(
+ name = name,
+ srcs = static_files,
+ )