summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/concept-changes.txt6
-rw-r--r--Documentation/config-gerrit.txt2
-rw-r--r--Documentation/rest-api-projects.txt8
-rw-r--r--Documentation/user-search.txt6
-rw-r--r--WORKSPACE9
-rw-r--r--java/com/google/gerrit/acceptance/AbstractDaemonTest.java2
-rw-r--r--java/com/google/gerrit/acceptance/TestProjectInput.java4
-rw-r--r--java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java37
-rw-r--r--java/com/google/gerrit/elasticsearch/BUILD1
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java2
-rw-r--r--java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java2
-rw-r--r--java/com/google/gerrit/extensions/api/projects/ProjectInput.java2
-rw-r--r--java/com/google/gerrit/extensions/registration/DynamicItem.java47
-rw-r--r--java/com/google/gerrit/extensions/registration/DynamicMap.java32
-rw-r--r--java/com/google/gerrit/extensions/registration/DynamicSet.java73
-rw-r--r--java/com/google/gerrit/extensions/registration/DynamicSetProvider.java7
-rw-r--r--java/com/google/gerrit/extensions/registration/Extension.java61
-rw-r--r--java/com/google/gerrit/gpg/GerritPublicKeyChecker.java18
-rw-r--r--java/com/google/gerrit/httpd/ProjectOAuthFilter.java4
-rw-r--r--java/com/google/gerrit/pgm/util/BatchProgramModule.java3
-rw-r--r--java/com/google/gerrit/server/StarredChangesUtil.java84
-rw-r--r--java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java2
-rw-r--r--java/com/google/gerrit/server/cache/CacheMetrics.java5
-rw-r--r--java/com/google/gerrit/server/change/ChangeJson.java6
-rw-r--r--java/com/google/gerrit/server/config/CanonicalWebUrlModule.java1
-rw-r--r--java/com/google/gerrit/server/config/ChangeCleanupConfig.java17
-rw-r--r--java/com/google/gerrit/server/config/DefaultBrowseUrls.java (renamed from java/com/google/gerrit/extensions/registration/NamedProvider.java)25
-rw-r--r--java/com/google/gerrit/server/config/ProjectConfigEntry.java6
-rw-r--r--java/com/google/gerrit/server/config/UrlFormatter.java66
-rw-r--r--java/com/google/gerrit/server/edit/ChangeEditJson.java3
-rw-r--r--java/com/google/gerrit/server/events/EventFactory.java16
-rw-r--r--java/com/google/gerrit/server/extensions/webui/UiActions.java3
-rw-r--r--java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java31
-rw-r--r--java/com/google/gerrit/server/git/MergeUtil.java31
-rw-r--r--java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java22
-rw-r--r--java/com/google/gerrit/server/git/receive/ReceiveCommits.java4
-rw-r--r--java/com/google/gerrit/server/git/validators/CommitValidators.java74
-rw-r--r--java/com/google/gerrit/server/git/validators/MergeValidators.java4
-rw-r--r--java/com/google/gerrit/server/logging/TraceContext.java20
-rw-r--r--java/com/google/gerrit/server/mail/receive/MailProcessor.java17
-rw-r--r--java/com/google/gerrit/server/mail/send/ChangeEmail.java7
-rw-r--r--java/com/google/gerrit/server/mail/send/EmailArguments.java9
-rw-r--r--java/com/google/gerrit/server/mail/send/OutgoingEmail.java2
-rw-r--r--java/com/google/gerrit/server/project/ContributorAgreementsChecker.java23
-rw-r--r--java/com/google/gerrit/server/project/CreateProjectArgs.java4
-rw-r--r--java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java18
-rw-r--r--java/com/google/gerrit/server/restapi/account/SetPreferences.java3
-rw-r--r--java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java3
-rw-r--r--java/com/google/gerrit/server/restapi/config/GetServerInfo.java7
-rw-r--r--java/com/google/gerrit/server/restapi/config/ListCaches.java3
-rw-r--r--java/com/google/gerrit/server/restapi/config/PostCaches.java3
-rw-r--r--java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java6
-rw-r--r--java/com/google/gerrit/server/restapi/project/CreateProject.java6
-rw-r--r--java/com/google/gerrit/server/restapi/project/GarbageCollect.java20
-rw-r--r--java/com/google/gerrit/server/restapi/project/ProjectsCollection.java5
-rw-r--r--java/com/google/gerrit/server/submit/MergeSorter.java5
-rw-r--r--java/com/google/gerrit/server/submit/RebaseSorter.java2
-rw-r--r--javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java4
-rw-r--r--javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java9
-rw-r--r--javatests/com/google/gerrit/extensions/registration/DynamicSetTest.java4
-rw-r--r--javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java2
-rw-r--r--javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java3
-rw-r--r--javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java37
-rw-r--r--lib/polymer_externs/BUILD9
m---------plugins/hooks0
m---------plugins/reviewnotes0
70 files changed, 599 insertions, 366 deletions
diff --git a/Documentation/concept-changes.txt b/Documentation/concept-changes.txt
index 7320a508f6..1d275b419a 100644
--- a/Documentation/concept-changes.txt
+++ b/Documentation/concept-changes.txt
@@ -55,7 +55,7 @@ are not required to review it.
|An optional topic.
|Strategy
-|The <<submit-strategy>> for the change.
+|The <<submit-strategies,submit strategy>> for the change.
|Code Review
|Displays the Code Review status for the change.
@@ -84,10 +84,10 @@ listed next to the change message. These related changes are grouped together in
several categories, including:
* Relation Chain. These changes are related by parent-child relationships,
- regardless of <<topics>>.
+ regardless of <<topic,topic>>.
* Merge Conflicts. These are changes in which there is a merge conflict with
the current change.
-* Submitted Together. These are changes that share the same <<topics>>.
+* Submitted Together. These are changes that share the same <<topic,topic>>.
An arrow indicates the change you are currently viewing.
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index f27434efa1..9f0bf8650e 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -690,7 +690,7 @@ H2 uses memory to cache its database content. The parameter `h2CacheSize`
allows to limit the memory used by H2 and thus prevent out-of-memory
caused by the H2 database using too much memory.
+
-See <<database.h2.cachesize,database.h2.cachesize>> for a detailed discussion.
+See <<database.h2.cacheSize,database.h2.cacheSize>> for a detailed discussion.
+
Default is unset, using up to half of the available memory.
+
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt
index b517d3c0d4..2a9dcee018 100644
--- a/Documentation/rest-api-projects.txt
+++ b/Documentation/rest-api-projects.txt
@@ -3570,6 +3570,12 @@ Whether the usage of Change-Ids is required for the project (`TRUE`,
`FALSE`, `INHERIT`).
This property is deprecated and will be removed in
a future release.
+|`enable_signed_push` |`INHERIT` if not set|
+Whether signed push validation is enabled on the project (`TRUE`,
+`FALSE`, `INHERIT`).
+|`require_signed_push` |`INHERIT` if not set|
+Whether signed push validation is required on the project (`TRUE`,
+`FALSE`, `INHERIT`).
|`max_object_size_limit` |optional|
Max allowed Git object size for this project.
Common unit suffixes of 'k', 'm', or 'g' are supported.
@@ -3707,8 +3713,6 @@ The path to the `GerritSiteHeader.html` file.
The path to the `GerritSiteFooter.html` file.
|=============================
-----
-
GERRIT
------
Part of link:index.html[Gerrit Code Review]
diff --git a/Documentation/user-search.txt b/Documentation/user-search.txt
index 41cb380908..7c904f5332 100644
--- a/Documentation/user-search.txt
+++ b/Documentation/user-search.txt
@@ -166,7 +166,7 @@ Changes occurring in 'PROJECT' or in one of the child projects of
'PROJECT'.
[[repository]]
-repository:'REPOSITORY'::
+repository:'REPOSITORY', repo:'REPOSITORY'::
+
Changes occurring in 'REPOSITORY'. If 'REPOSITORY' starts with `^` it
matches repository names by regular expression. The
@@ -174,12 +174,12 @@ link:http://www.brics.dk/automaton/[dk.brics.automaton
library] is used for evaluation of such patterns.
[[repositories]]
-repositories:'PREFIX'::
+repositories:'PREFIX', repos:'PREFIX'::
+
Changes occurring in repositories starting with 'PREFIX'.
[[parentrepository]]
-parentrepository:'REPOSITORY'::
+parentrepository:'REPOSITORY', parentrepo:'REPOSITORY'::
+
Changes occurring in 'REPOSITORY' or in one of the child repositories of
'REPOSITORY'.
diff --git a/WORKSPACE b/WORKSPACE
index 22dffd5aff..a20e0b18f3 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -25,6 +25,7 @@ http_archive(
# https://github.com/google/closure-compiler/blob/master/contrib/externs/polymer-1.0.js
http_file(
name = "polymer_closure",
+ downloaded_file_path = "polymer_closure.js",
sha256 = "5a589bdba674e1fec7188e9251c8624ebf2d4d969beb6635f9148f420d1e08b1",
urls = ["https://raw.githubusercontent.com/google/closure-compiler/775609aad61e14aef289ebec4bfc09ad88877f9e/contrib/externs/polymer-1.0.js"],
)
@@ -1066,14 +1067,14 @@ maven_jar(
maven_jar(
name = "asciidoctor",
- artifact = "org.asciidoctor:asciidoctorj:1.5.6",
- sha1 = "bb757d4b8b0f8438ce2ed781f6688cc6c01d9237",
+ artifact = "org.asciidoctor:asciidoctorj:1.5.7",
+ sha1 = "8e8c1d8fc6144405700dd8df3b177f2801ac5987",
)
maven_jar(
name = "jruby",
- artifact = "org.jruby:jruby-complete:9.1.13.0",
- sha1 = "8903bf42272062e87a7cbc1d98919e0729a9939f",
+ artifact = "org.jruby:jruby-complete:9.1.17.0",
+ sha1 = "76716d529710fc03d1d429b43e3cedd4419f78d4",
)
maven_jar(
diff --git a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index bd7d65d6a5..030ec2a528 100644
--- a/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -502,6 +502,8 @@ public abstract class AbstractDaemonTest {
in.useSignedOffBy = ann.useSignedOffBy();
in.useContentMerge = ann.useContentMerge();
in.rejectEmptyCommit = ann.rejectEmptyCommit();
+ in.enableSignedPush = ann.enableSignedPush();
+ in.requireSignedPush = ann.requireSignedPush();
} else {
// Defaults should match TestProjectConfig, omitting nullable values.
in.createEmptyCommit = true;
diff --git a/java/com/google/gerrit/acceptance/TestProjectInput.java b/java/com/google/gerrit/acceptance/TestProjectInput.java
index eada6434c2..0a3686b543 100644
--- a/java/com/google/gerrit/acceptance/TestProjectInput.java
+++ b/java/com/google/gerrit/acceptance/TestProjectInput.java
@@ -47,6 +47,10 @@ public @interface TestProjectInput {
InheritableBoolean rejectEmptyCommit() default InheritableBoolean.INHERIT;
+ InheritableBoolean enableSignedPush() default InheritableBoolean.INHERIT;
+
+ InheritableBoolean requireSignedPush() default InheritableBoolean.INHERIT;
+
// Fields specific to acceptance test behavior.
/** Username to use for initial clone, passed to {@link AccountCreator}. */
diff --git a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
index 2c1c93a1ba..fec7137094 100644
--- a/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
+++ b/java/com/google/gerrit/elasticsearch/AbstractElasticIndex.java
@@ -26,6 +26,7 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.CharStreams;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
import com.google.gerrit.elasticsearch.builders.QueryBuilder;
import com.google.gerrit.elasticsearch.builders.SearchSourceBuilder;
@@ -160,7 +161,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
@Override
public void delete(K id) throws IOException {
String uri = getURI(type, BULK);
- Response response = postRequest(getDeleteActions(id), uri, getRefreshParam());
+ Response response = postRequest(uri, getDeleteActions(id), getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
@@ -172,10 +173,10 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
public void deleteAll() throws IOException {
// Delete the index, if it exists.
String endpoint = indexName + client.adapter().indicesExistParam();
- Response response = client.get().performRequest(new Request("HEAD", endpoint));
+ Response response = performRequest("HEAD", endpoint);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
- response = client.get().performRequest(new Request("DELETE", indexName));
+ response = performRequest("DELETE", indexName);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
@@ -185,7 +186,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
// Recreate the index.
String indexCreationFields = concatJsonString(getSettings(), getMappings());
- response = performRequest("PUT", indexCreationFields, indexName, Collections.emptyMap());
+ response = performRequest("PUT", indexName, indexCreationFields);
statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
String error = String.format("Failed to create index %s: %s", indexName, statusCode);
@@ -297,20 +298,36 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
return encodedIndexName + "/" + encodedType + "/" + request;
}
- protected Response postRequest(Object payload, String uri, Map<String, String> params)
+ protected Response postRequest(String uri, Object payload) throws IOException {
+ return performRequest("POST", uri, payload);
+ }
+
+ protected Response postRequest(String uri, Object payload, Map<String, String> params)
throws IOException {
- return performRequest("POST", payload, uri, params);
+ return performRequest("POST", uri, payload, params);
}
private String concatJsonString(String target, String addition) {
return target.substring(0, target.length() - 1) + "," + addition.substring(1);
}
+ private Response performRequest(String method, String uri) throws IOException {
+ return performRequest(method, uri, null);
+ }
+
+ private Response performRequest(String method, String uri, @Nullable Object payload)
+ throws IOException {
+ return performRequest(method, uri, payload, Collections.emptyMap());
+ }
+
private Response performRequest(
- String method, Object payload, String uri, Map<String, String> params) throws IOException {
- Request request = new Request(method, uri);
- String payloadStr = payload instanceof String ? (String) payload : payload.toString();
- request.setEntity(new NStringEntity(payloadStr, ContentType.APPLICATION_JSON));
+ String method, String uri, @Nullable Object payload, Map<String, String> params)
+ throws IOException {
+ Request request = new Request(method, uri.startsWith("/") ? uri : "/" + uri);
+ if (payload != null) {
+ String payloadStr = payload instanceof String ? (String) payload : payload.toString();
+ request.setEntity(new NStringEntity(payloadStr, ContentType.APPLICATION_JSON));
+ }
for (Map.Entry<String, String> entry : params.entrySet()) {
request.addParameter(entry.getKey(), entry.getValue());
}
diff --git a/java/com/google/gerrit/elasticsearch/BUILD b/java/com/google/gerrit/elasticsearch/BUILD
index 31ede79f16..8d23051517 100644
--- a/java/com/google/gerrit/elasticsearch/BUILD
+++ b/java/com/google/gerrit/elasticsearch/BUILD
@@ -3,6 +3,7 @@ java_library(
srcs = glob(["**/*.java"]),
visibility = ["//visibility:public"],
deps = [
+ "//java/com/google/gerrit/common:annotations",
"//java/com/google/gerrit/extensions:api",
"//java/com/google/gerrit/index",
"//java/com/google/gerrit/index:query_exception",
diff --git a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
index d18af423f5..1b69b6d295 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticAccountIndex.java
@@ -79,7 +79,7 @@ public class ElasticAccountIndex extends AbstractElasticIndex<Account.Id, Accoun
.add(new UpdateRequest<>(schema, as));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
index f6af79f228..d7c8b00039 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticChangeIndex.java
@@ -138,7 +138,7 @@ class ElasticChangeIndex extends AbstractElasticIndex<Change.Id, ChangeData>
}
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
index bf6b962304..f694a05482 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticGroupIndex.java
@@ -77,7 +77,7 @@ public class ElasticGroupIndex extends AbstractElasticIndex<AccountGroup.UUID, I
.add(new UpdateRequest<>(schema, group));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
index 623f62c439..8510559791 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticProjectIndex.java
@@ -77,7 +77,7 @@ public class ElasticProjectIndex extends AbstractElasticIndex<Project.NameKey, P
.add(new UpdateRequest<>(schema, projectState));
String uri = getURI(type, BULK);
- Response response = postRequest(bulk, uri, getRefreshParam());
+ Response response = postRequest(uri, bulk, getRefreshParam());
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
throw new IOException(
diff --git a/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java b/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
index 8cb69e0179..05fd7a7afc 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticQueryAdapter.java
@@ -33,7 +33,7 @@ public class ElasticQueryAdapter {
ElasticQueryAdapter(ElasticVersion version) {
this.ignoreUnmapped = version == ElasticVersion.V2_4;
this.usePostV5Type = version.isV6();
- this.versionDiscoveryUrl = version.isV6() ? "%s*" : "%s*/_aliases";
+ this.versionDiscoveryUrl = version.isV6() ? "/%s*" : "/%s*/_aliases";
switch (version) {
case V5_6:
diff --git a/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java b/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
index 337f2ca882..e9839b7978 100644
--- a/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
+++ b/java/com/google/gerrit/elasticsearch/ElasticRestClientProvider.java
@@ -106,7 +106,7 @@ class ElasticRestClientProvider implements Provider<RestClient>, LifecycleListen
private ElasticVersion getVersion() throws ElasticException {
try {
- Response response = client.performRequest(new Request("GET", ""));
+ Response response = client.performRequest(new Request("GET", "/"));
StatusLine statusLine = response.getStatusLine();
if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
throw new FailedToGetVersion(statusLine);
diff --git a/java/com/google/gerrit/extensions/api/projects/ProjectInput.java b/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
index b7079ae1ee..e61d316a0a 100644
--- a/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
+++ b/java/com/google/gerrit/extensions/api/projects/ProjectInput.java
@@ -34,6 +34,8 @@ public class ProjectInput {
public InheritableBoolean requireChangeId;
public InheritableBoolean createNewChangeForAllNotInTarget;
public InheritableBoolean rejectEmptyCommit;
+ public InheritableBoolean enableSignedPush;
+ public InheritableBoolean requireSignedPush;
public String maxObjectSizeLimit;
public Map<String, Map<String, ConfigValue>> pluginConfigValues;
}
diff --git a/java/com/google/gerrit/extensions/registration/DynamicItem.java b/java/com/google/gerrit/extensions/registration/DynamicItem.java
index 4f36ab4817..67982d9040 100644
--- a/java/com/google/gerrit/extensions/registration/DynamicItem.java
+++ b/java/com/google/gerrit/extensions/registration/DynamicItem.java
@@ -111,17 +111,22 @@ public class DynamicItem<T> {
}
private final Key<DynamicItem<T>> key;
- private final AtomicReference<NamedProvider<T>> ref;
+ private final AtomicReference<Extension<T>> ref;
DynamicItem(Key<DynamicItem<T>> key, Provider<T> provider, String pluginName) {
- NamedProvider<T> in = null;
+ Extension<T> in = null;
if (provider != null) {
- in = new NamedProvider<>(provider, pluginName);
+ in = new Extension<>(pluginName, provider);
}
this.key = key;
this.ref = new AtomicReference<>(in);
}
+ @Nullable
+ public Extension<T> getEntry() {
+ return ref.get();
+ }
+
/**
* Get the configured item, or null.
*
@@ -130,8 +135,8 @@ public class DynamicItem<T> {
*/
@Nullable
public T get() {
- NamedProvider<T> item = ref.get();
- return item != null ? item.impl.get() : null;
+ Extension<T> item = ref.get();
+ return item != null ? item.get() : null;
}
/**
@@ -143,8 +148,8 @@ public class DynamicItem<T> {
*/
@Nullable
public String getPluginName() {
- NamedProvider<T> item = ref.get();
- return item != null ? item.pluginName : null;
+ Extension<T> item = ref.get();
+ return item != null ? item.getPluginName() : null;
}
/**
@@ -166,19 +171,19 @@ public class DynamicItem<T> {
* @return handle to remove the item at a later point in time.
*/
public RegistrationHandle set(Provider<T> impl, String pluginName) {
- final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
- NamedProvider<T> old = null;
+ final Extension<T> item = new Extension<>(pluginName, impl);
+ Extension<T> old = null;
while (!ref.compareAndSet(old, item)) {
old = ref.get();
- if (old != null && !PluginName.GERRIT.equals(old.pluginName)) {
+ if (old != null && !PluginName.GERRIT.equals(old.getPluginName())) {
throw new ProvisionException(
String.format(
"%s already provided by %s, ignoring plugin %s",
- key.getTypeLiteral(), old.pluginName, pluginName));
+ key.getTypeLiteral(), old.getPluginName(), pluginName));
}
}
- final NamedProvider<T> defaultItem = old;
+ final Extension<T> defaultItem = old;
return new RegistrationHandle() {
@Override
public void remove() {
@@ -198,13 +203,13 @@ public class DynamicItem<T> {
* @return a handle that can remove this item later, or hot-swap the item.
*/
public ReloadableRegistrationHandle<T> set(Key<T> key, Provider<T> impl, String pluginName) {
- final NamedProvider<T> item = new NamedProvider<>(impl, pluginName);
- NamedProvider<T> old = null;
+ final Extension<T> item = new Extension<>(pluginName, impl);
+ Extension<T> old = null;
while (!ref.compareAndSet(old, item)) {
old = ref.get();
if (old != null
- && !PluginName.GERRIT.equals(old.pluginName)
- && !pluginName.equals(old.pluginName)) {
+ && !PluginName.GERRIT.equals(old.getPluginName())
+ && !pluginName.equals(old.getPluginName())) {
// We allow to replace:
// 1. Gerrit core items, e.g. websession cache
// can be replaced by plugin implementation
@@ -212,7 +217,7 @@ public class DynamicItem<T> {
throw new ProvisionException(
String.format(
"%s already provided by %s, ignoring plugin %s",
- this.key.getTypeLiteral(), old.pluginName, pluginName));
+ this.key.getTypeLiteral(), old.getPluginName(), pluginName));
}
}
return new ReloadableHandle(key, item, old);
@@ -220,10 +225,10 @@ public class DynamicItem<T> {
private class ReloadableHandle implements ReloadableRegistrationHandle<T> {
private final Key<T> handleKey;
- private final NamedProvider<T> item;
- private final NamedProvider<T> defaultItem;
+ private final Extension<T> item;
+ private final Extension<T> defaultItem;
- ReloadableHandle(Key<T> handleKey, NamedProvider<T> item, NamedProvider<T> defaultItem) {
+ ReloadableHandle(Key<T> handleKey, Extension<T> item, Extension<T> defaultItem) {
this.handleKey = handleKey;
this.item = item;
this.defaultItem = defaultItem;
@@ -242,7 +247,7 @@ public class DynamicItem<T> {
@Override
@Nullable
public ReloadableHandle replace(Key<T> newKey, Provider<T> newItem) {
- NamedProvider<T> n = new NamedProvider<>(newItem, item.pluginName);
+ Extension<T> n = new Extension<>(item.getPluginName(), newItem);
if (ref.compareAndSet(item, n)) {
return new ReloadableHandle(newKey, n, defaultItem);
}
diff --git a/java/com/google/gerrit/extensions/registration/DynamicMap.java b/java/com/google/gerrit/extensions/registration/DynamicMap.java
index 96d19b2090..48b1279489 100644
--- a/java/com/google/gerrit/extensions/registration/DynamicMap.java
+++ b/java/com/google/gerrit/extensions/registration/DynamicMap.java
@@ -40,29 +40,7 @@ import java.util.concurrent.ConcurrentMap;
* resolve the provider to an instance on demand. This enables registrations to decide between
* singleton and non-singleton members.
*/
-public abstract class DynamicMap<T> implements Iterable<DynamicMap.Entry<T>> {
- public static class Entry<T> {
- private final NamePair namePair;
- private final Provider<T> provider;
-
- private Entry(NamePair namePair, Provider<T> provider) {
- this.namePair = namePair;
- this.provider = provider;
- }
-
- public String getPluginName() {
- return namePair.pluginName;
- }
-
- public String getExportName() {
- return namePair.exportName;
- }
-
- public Provider<T> getProvider() {
- return provider;
- }
- }
-
+public abstract class DynamicMap<T> implements Iterable<Extension<T>> {
/**
* Declare a singleton {@code DynamicMap<T>} with a binder.
*
@@ -166,18 +144,18 @@ public abstract class DynamicMap<T> implements Iterable<DynamicMap.Entry<T>> {
/** Iterate through all entries in an undefined order. */
@Override
- public Iterator<Entry<T>> iterator() {
+ public Iterator<Extension<T>> iterator() {
final Iterator<Map.Entry<NamePair, Provider<T>>> i = items.entrySet().iterator();
- return new Iterator<Entry<T>>() {
+ return new Iterator<Extension<T>>() {
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
- public Entry<T> next() {
+ public Extension<T> next() {
Map.Entry<NamePair, Provider<T>> e = i.next();
- return new Entry<>(e.getKey(), e.getValue());
+ return new Extension<>(e.getKey().pluginName, e.getKey().exportName, e.getValue());
}
@Override
diff --git a/java/com/google/gerrit/extensions/registration/DynamicSet.java b/java/com/google/gerrit/extensions/registration/DynamicSet.java
index 6b3a49bffe..dcd0d8f1b0 100644
--- a/java/com/google/gerrit/extensions/registration/DynamicSet.java
+++ b/java/com/google/gerrit/extensions/registration/DynamicSet.java
@@ -45,24 +45,6 @@ import java.util.concurrent.atomic.AtomicReference;
* singleton and non-singleton members.
*/
public class DynamicSet<T> implements Iterable<T> {
- public static class Entry<T> {
- private final String pluginName;
- private final Provider<T> provider;
-
- private Entry(String pluginName, Provider<T> provider) {
- this.pluginName = pluginName;
- this.provider = provider;
- }
-
- public String getPluginName() {
- return pluginName;
- }
-
- public Provider<T> getProvider() {
- return provider;
- }
- }
-
/**
* Declare a singleton {@code DynamicSet<T>} with a binder.
*
@@ -153,12 +135,12 @@ public class DynamicSet<T> implements Iterable<T> {
}
public static <T> DynamicSet<T> emptySet() {
- return new DynamicSet<>(Collections.<AtomicReference<NamedProvider<T>>>emptySet());
+ return new DynamicSet<>(Collections.<AtomicReference<Extension<T>>>emptySet());
}
- private final CopyOnWriteArrayList<AtomicReference<NamedProvider<T>>> items;
+ private final CopyOnWriteArrayList<AtomicReference<Extension<T>>> items;
- DynamicSet(Collection<AtomicReference<NamedProvider<T>>> base) {
+ DynamicSet(Collection<AtomicReference<Extension<T>>> base) {
items = new CopyOnWriteArrayList<>(base);
}
@@ -168,7 +150,7 @@ public class DynamicSet<T> implements Iterable<T> {
@Override
public Iterator<T> iterator() {
- Iterator<Entry<T>> entryIterator = entries().iterator();
+ Iterator<Extension<T>> entryIterator = entries().iterator();
return new Iterator<T>() {
@Override
public boolean hasNext() {
@@ -177,39 +159,35 @@ public class DynamicSet<T> implements Iterable<T> {
@Override
public T next() {
- Entry<T> next = entryIterator.next();
+ Extension<T> next = entryIterator.next();
return next != null ? next.getProvider().get() : null;
}
};
}
- public Iterable<Entry<T>> entries() {
- final Iterator<AtomicReference<NamedProvider<T>>> itr = items.iterator();
- return new Iterable<Entry<T>>() {
+ public Iterable<Extension<T>> entries() {
+ final Iterator<AtomicReference<Extension<T>>> itr = items.iterator();
+ return new Iterable<Extension<T>>() {
@Override
- public Iterator<Entry<T>> iterator() {
- return new Iterator<Entry<T>>() {
- private Entry<T> next;
+ public Iterator<Extension<T>> iterator() {
+ return new Iterator<Extension<T>>() {
+ private Extension<T> next;
@Override
public boolean hasNext() {
while (next == null && itr.hasNext()) {
- NamedProvider<T> p = itr.next().get();
+ Extension<T> p = itr.next().get();
if (p != null) {
- try {
- next = new Entry<>(p.pluginName, p.impl);
- } catch (RuntimeException e) {
- // TODO Log failed member of DynamicSet.
- }
+ next = p;
}
}
return next != null;
}
@Override
- public Entry<T> next() {
+ public Extension<T> next() {
if (hasNext()) {
- Entry<T> result = next;
+ Extension<T> result = next;
next = null;
return result;
}
@@ -250,7 +228,7 @@ public class DynamicSet<T> implements Iterable<T> {
public ImmutableSortedSet<String> plugins() {
return items
.stream()
- .map(i -> i.get().pluginName)
+ .map(i -> i.get().getPluginName())
.collect(toImmutableSortedSet(naturalOrder()));
}
@@ -263,8 +241,8 @@ public class DynamicSet<T> implements Iterable<T> {
public ImmutableSet<Provider<T>> byPlugin(String pluginName) {
return items
.stream()
- .filter(i -> i.get().pluginName.equals(pluginName))
- .map(i -> i.get().impl)
+ .filter(i -> i.get().getPluginName().equals(pluginName))
+ .map(i -> i.get().getProvider())
.collect(toImmutableSet());
}
@@ -285,8 +263,8 @@ public class DynamicSet<T> implements Iterable<T> {
* @return handle to remove the item at a later point in time.
*/
public RegistrationHandle add(String pluginName, Provider<T> item) {
- final AtomicReference<NamedProvider<T>> ref =
- new AtomicReference<>(new NamedProvider<>(item, pluginName));
+ final AtomicReference<Extension<T>> ref =
+ new AtomicReference<>(new Extension<>(pluginName, item));
items.add(ref);
return new RegistrationHandle() {
@Override
@@ -310,18 +288,17 @@ public class DynamicSet<T> implements Iterable<T> {
* the collection.
*/
public ReloadableRegistrationHandle<T> add(String pluginName, Key<T> key, Provider<T> item) {
- AtomicReference<NamedProvider<T>> ref =
- new AtomicReference<>(new NamedProvider<>(item, pluginName));
+ AtomicReference<Extension<T>> ref = new AtomicReference<>(new Extension<>(pluginName, item));
items.add(ref);
return new ReloadableHandle(ref, key, ref.get());
}
private class ReloadableHandle implements ReloadableRegistrationHandle<T> {
- private final AtomicReference<NamedProvider<T>> ref;
+ private final AtomicReference<Extension<T>> ref;
private final Key<T> key;
- private final NamedProvider<T> item;
+ private final Extension<T> item;
- ReloadableHandle(AtomicReference<NamedProvider<T>> ref, Key<T> key, NamedProvider<T> item) {
+ ReloadableHandle(AtomicReference<Extension<T>> ref, Key<T> key, Extension<T> item) {
this.ref = ref;
this.key = key;
this.item = item;
@@ -341,7 +318,7 @@ public class DynamicSet<T> implements Iterable<T> {
@Override
public ReloadableHandle replace(Key<T> newKey, Provider<T> newItem) {
- NamedProvider<T> n = new NamedProvider<>(newItem, item.pluginName);
+ Extension<T> n = new Extension<>(item.getPluginName(), newItem);
if (ref.compareAndSet(item, n)) {
return new ReloadableHandle(ref, newKey, n);
}
diff --git a/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java b/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
index 6d36f54bb3..832933b31c 100644
--- a/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
+++ b/java/com/google/gerrit/extensions/registration/DynamicSetProvider.java
@@ -38,17 +38,16 @@ class DynamicSetProvider<T> implements Provider<DynamicSet<T>> {
return new DynamicSet<>(find(injector, type));
}
- private static <T> List<AtomicReference<NamedProvider<T>>> find(
- Injector src, TypeLiteral<T> type) {
+ private static <T> List<AtomicReference<Extension<T>>> find(Injector src, TypeLiteral<T> type) {
List<Binding<T>> bindings = src.findBindingsByType(type);
int cnt = bindings != null ? bindings.size() : 0;
if (cnt == 0) {
return Collections.emptyList();
}
- List<AtomicReference<NamedProvider<T>>> r = new ArrayList<>(cnt);
+ List<AtomicReference<Extension<T>>> r = new ArrayList<>(cnt);
for (Binding<T> b : bindings) {
if (b.getKey().getAnnotation() != null) {
- r.add(new AtomicReference<>(new NamedProvider<>(b.getProvider(), PluginName.GERRIT)));
+ r.add(new AtomicReference<>(new Extension<>(PluginName.GERRIT, b.getProvider())));
}
}
return r;
diff --git a/java/com/google/gerrit/extensions/registration/Extension.java b/java/com/google/gerrit/extensions/registration/Extension.java
new file mode 100644
index 0000000000..aaec201bd7
--- /dev/null
+++ b/java/com/google/gerrit/extensions/registration/Extension.java
@@ -0,0 +1,61 @@
+// 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.extensions.registration;
+
+import com.google.gerrit.common.Nullable;
+import com.google.inject.Provider;
+
+/**
+ * An extension that is provided by a plugin.
+ *
+ * <p>Contains the name of the plugin that provides the extension, the extension point
+ * implementation and optionally the export name under which the extension was exported.
+ *
+ * <p>An export name is only available if this extension is an entry in a {@link DynamicMap}.
+ *
+ * @param <T> Type of extension point that this extension implements
+ */
+public class Extension<T> {
+ private final String pluginName;
+ private final @Nullable String exportName;
+ private final Provider<T> provider;
+
+ protected Extension(String pluginName, Provider<T> provider) {
+ this(pluginName, null, provider);
+ }
+
+ protected Extension(String pluginName, @Nullable String exportName, Provider<T> provider) {
+ this.pluginName = pluginName;
+ this.exportName = exportName;
+ this.provider = provider;
+ }
+
+ public String getPluginName() {
+ return pluginName;
+ }
+
+ @Nullable
+ public String getExportName() {
+ return exportName;
+ }
+
+ public Provider<T> getProvider() {
+ return provider;
+ }
+
+ public T get() {
+ return provider.get();
+ }
+}
diff --git a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
index bc0cd899f8..b6fb46e60d 100644
--- a/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
+++ b/java/com/google/gerrit/gpg/GerritPublicKeyChecker.java
@@ -22,12 +22,11 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
-import com.google.gerrit.common.PageLinks;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.externalids.ExternalId;
-import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.query.account.InternalAccountQuery;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
@@ -38,6 +37,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -58,7 +58,7 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
@Singleton
public static class Factory {
private final Provider<InternalAccountQuery> accountQueryProvider;
- private final String webUrl;
+ private final UrlFormatter urlFormatter;
private final IdentifiedUser.GenericFactory userFactory;
private final int maxTrustDepth;
private final ImmutableMap<Long, Fingerprint> trusted;
@@ -68,9 +68,9 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
@GerritServerConfig Config cfg,
Provider<InternalAccountQuery> accountQueryProvider,
IdentifiedUser.GenericFactory userFactory,
- @CanonicalWebUrl String webUrl) {
+ UrlFormatter urlFormatter) {
this.accountQueryProvider = accountQueryProvider;
- this.webUrl = webUrl;
+ this.urlFormatter = urlFormatter;
this.userFactory = userFactory;
this.maxTrustDepth = cfg.getInt("receive", null, "maxTrustDepth", 0);
@@ -101,14 +101,14 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
}
private final Provider<InternalAccountQuery> accountQueryProvider;
- private final String webUrl;
+ private final UrlFormatter urlFormatter;
private final IdentifiedUser.GenericFactory userFactory;
private IdentifiedUser expectedUser;
private GerritPublicKeyChecker(Factory factory) {
this.accountQueryProvider = factory.accountQueryProvider;
- this.webUrl = factory.webUrl;
+ this.urlFormatter = factory.urlFormatter;
this.userFactory = factory.userFactory;
if (factory.trusted != null) {
enableTrust(factory.maxTrustDepth, factory.trusted);
@@ -144,8 +144,10 @@ public class GerritPublicKeyChecker extends PublicKeyChecker {
private CheckResult checkIdsForExpectedUser(PGPPublicKey key) throws PGPException {
Set<String> allowedUserIds = getAllowedUserIds(expectedUser);
if (allowedUserIds.isEmpty()) {
+ Optional<String> settings = urlFormatter.getSettingsUrl("Identities");
return CheckResult.bad(
- "No identities found for user; check " + webUrl + "#" + PageLinks.SETTINGS_WEBIDENT);
+ "No identities found for user"
+ + (settings.isPresent() ? "; check " + settings.get() : ""));
}
if (hasAllowedUserId(key, allowedUserIds)) {
return CheckResult.trusted();
diff --git a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
index 5e234d2e38..30ebe6e7cb 100644
--- a/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
+++ b/java/com/google/gerrit/httpd/ProjectOAuthFilter.java
@@ -25,7 +25,7 @@ import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.auth.oauth.OAuthLoginProvider;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicMap.Entry;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.AccessPath;
import com.google.gerrit.server.account.AccountCache;
@@ -191,7 +191,7 @@ class ProjectOAuthFilter implements Filter {
*/
private void pickOnlyProvider() throws ServletException {
try {
- Entry<OAuthLoginProvider> loginProvider = Iterables.getOnlyElement(loginProviders);
+ Extension<OAuthLoginProvider> loginProvider = Iterables.getOnlyElement(loginProviders);
defaultAuthPlugin = loginProvider.getPluginName();
defaultAuthProvider = loginProvider.getExportName();
} catch (NoSuchElementException e) {
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index 683a205646..b316d3a7a8 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -47,12 +47,14 @@ import com.google.gerrit.server.change.RebaseChangeOp;
import com.google.gerrit.server.config.AdministrateServerGroups;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.CanonicalWebUrlProvider;
+import com.google.gerrit.server.config.DefaultBrowseUrls;
import com.google.gerrit.server.config.DisableReverseDnsLookup;
import com.google.gerrit.server.config.DisableReverseDnsLookupProvider;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GitReceivePackGroups;
import com.google.gerrit.server.config.GitUploadPackGroups;
import com.google.gerrit.server.config.SysExecutorModule;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.extensions.events.EventUtil;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.extensions.events.RevisionCreated;
@@ -138,6 +140,7 @@ public class BatchProgramModule extends FactoryModule {
bind(String.class)
.annotatedWith(CanonicalWebUrl.class)
.toProvider(CanonicalWebUrlProvider.class);
+ bind(UrlFormatter.class).to(DefaultBrowseUrls.class);
bind(Boolean.class)
.annotatedWith(DisableReverseDnsLookup.class)
.toProvider(DisableReverseDnsLookupProvider.class)
diff --git a/java/com/google/gerrit/server/StarredChangesUtil.java b/java/com/google/gerrit/server/StarredChangesUtil.java
index fa6cd6c61a..29974e9941 100644
--- a/java/com/google/gerrit/server/StarredChangesUtil.java
+++ b/java/com/google/gerrit/server/StarredChangesUtil.java
@@ -42,6 +42,8 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.index.change.ChangeIndexer;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -376,20 +378,20 @@ public class StarredChangesUtil {
}
public static StarRef readLabels(Repository repo, String refName) throws IOException {
- logger.atFine().log("Read star labels from %s", refName);
-
- Ref ref = repo.exactRef(refName);
- if (ref == null) {
- return StarRef.MISSING;
- }
+ try (TraceTimer traceTimer = TraceContext.newTimer("Read star labels from %s", refName)) {
+ Ref ref = repo.exactRef(refName);
+ if (ref == null) {
+ return StarRef.MISSING;
+ }
- try (ObjectReader reader = repo.newObjectReader()) {
- ObjectLoader obj = reader.open(ref.getObjectId(), Constants.OBJ_BLOB);
- return StarRef.create(
- ref,
- Splitter.on(CharMatcher.whitespace())
- .omitEmptyStrings()
- .split(new String(obj.getCachedBytes(Integer.MAX_VALUE), UTF_8)));
+ try (ObjectReader reader = repo.newObjectReader()) {
+ ObjectLoader obj = reader.open(ref.getObjectId(), Constants.OBJ_BLOB);
+ return StarRef.create(
+ ref,
+ Splitter.on(CharMatcher.whitespace())
+ .omitEmptyStrings()
+ .split(new String(obj.getCachedBytes(Integer.MAX_VALUE), UTF_8)));
+ }
}
}
@@ -450,8 +452,9 @@ public class StarredChangesUtil {
private void updateLabels(
Repository repo, String refName, ObjectId oldObjectId, Collection<String> labels)
throws IOException, OrmException, InvalidLabelsException {
- logger.atFine().log("Update star labels in %s (labels=%s)", refName, labels);
- try (RevWalk rw = new RevWalk(repo)) {
+ try (TraceTimer traceTimer =
+ TraceContext.newTimer("Update star labels in %s (labels=%s)", refName, labels);
+ RevWalk rw = new RevWalk(repo)) {
RefUpdate u = repo.updateRef(refName);
u.setExpectedOldObjectId(oldObjectId);
u.setForceUpdate(true);
@@ -488,31 +491,32 @@ public class StarredChangesUtil {
return;
}
- logger.atFine().log("Delete star labels in %s", refName);
- RefUpdate u = repo.updateRef(refName);
- u.setForceUpdate(true);
- u.setExpectedOldObjectId(oldObjectId);
- u.setRefLogIdent(serverIdent.get());
- u.setRefLogMessage("Unstar change", true);
- RefUpdate.Result result = u.delete();
- switch (result) {
- case FORCED:
- gitRefUpdated.fire(allUsers, u, null);
- return;
- case NEW:
- case NO_CHANGE:
- case FAST_FORWARD:
- case IO_FAILURE:
- case LOCK_FAILURE:
- case NOT_ATTEMPTED:
- case REJECTED:
- case REJECTED_CURRENT_BRANCH:
- case RENAMED:
- case REJECTED_MISSING_OBJECT:
- case REJECTED_OTHER_REASON:
- default:
- throw new OrmException(
- String.format("Delete star ref %s failed: %s", refName, result.name()));
+ try (TraceTimer traceTimer = TraceContext.newTimer("Delete star labels in %s", refName)) {
+ RefUpdate u = repo.updateRef(refName);
+ u.setForceUpdate(true);
+ u.setExpectedOldObjectId(oldObjectId);
+ u.setRefLogIdent(serverIdent.get());
+ u.setRefLogMessage("Unstar change", true);
+ RefUpdate.Result result = u.delete();
+ switch (result) {
+ case FORCED:
+ gitRefUpdated.fire(allUsers, u, null);
+ return;
+ case NEW:
+ case NO_CHANGE:
+ case FAST_FORWARD:
+ case IO_FAILURE:
+ case LOCK_FAILURE:
+ case NOT_ATTEMPTED:
+ case REJECTED:
+ case REJECTED_CURRENT_BRANCH:
+ case RENAMED:
+ case REJECTED_MISSING_OBJECT:
+ case REJECTED_OTHER_REASON:
+ default:
+ throw new OrmException(
+ String.format("Delete star ref %s failed: %s", refName, result.name()));
+ }
}
}
}
diff --git a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
index b117888892..9dd9bd89f8 100644
--- a/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
+++ b/java/com/google/gerrit/server/account/externalids/ExternalIdNotes.java
@@ -656,7 +656,7 @@ public class ExternalIdNotes extends VersionedMetaData {
@Override
protected void onLoad() throws IOException, ConfigInvalidException {
- logger.atFine().log("Reading external IDs");
+ logger.atFine().log("Reading external ID note map");
noteMap = revision != null ? NoteMap.read(reader, revision) : NoteMap.newEmptyMap();
diff --git a/java/com/google/gerrit/server/cache/CacheMetrics.java b/java/com/google/gerrit/server/cache/CacheMetrics.java
index 343565266f..c652d50d73 100644
--- a/java/com/google/gerrit/server/cache/CacheMetrics.java
+++ b/java/com/google/gerrit/server/cache/CacheMetrics.java
@@ -18,6 +18,7 @@ import com.google.common.cache.Cache;
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableSet;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.registration.PluginName;
import com.google.gerrit.metrics.CallbackMetric;
import com.google.gerrit.metrics.CallbackMetric1;
@@ -71,7 +72,7 @@ public class CacheMetrics {
metrics.newTrigger(
cacheMetrics,
() -> {
- for (DynamicMap.Entry<Cache<?, ?>> e : cacheMap) {
+ for (Extension<Cache<?, ?>> e : cacheMap) {
Cache<?, ?> c = e.getProvider().get();
String name = metricNameOf(e);
CacheStats cstats = c.stats();
@@ -95,7 +96,7 @@ public class CacheMetrics {
return ((double) d.hitCount() / d.requestCount() * 100);
}
- private static String metricNameOf(DynamicMap.Entry<Cache<?, ?>> e) {
+ private static String metricNameOf(Extension<Cache<?, ?>> e) {
if (PluginName.GERRIT.equals(e.getPluginName())) {
return e.getExportName();
}
diff --git a/java/com/google/gerrit/server/change/ChangeJson.java b/java/com/google/gerrit/server/change/ChangeJson.java
index 43f7b2f742..5de50f680f 100644
--- a/java/com/google/gerrit/server/change/ChangeJson.java
+++ b/java/com/google/gerrit/server/change/ChangeJson.java
@@ -88,6 +88,7 @@ import com.google.gerrit.extensions.common.WebLinkInfo;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.index.query.QueryResult;
@@ -340,6 +341,7 @@ public class ChangeJson {
this.enableParallelFormatting = config.getBoolean("change", "enableParallelFormatting", false);
this.fanOutExecutor = fanOutExecutor;
this.options = Sets.immutableEnumSet(options);
+ logger.atFine().log("options = %s", options);
}
/**
@@ -1471,7 +1473,7 @@ public class ChangeJson {
private Map<String, FetchInfo> makeFetchMap(ChangeData cd, PatchSet in)
throws PermissionBackendException, OrmException, IOException {
Map<String, FetchInfo> r = new LinkedHashMap<>();
- for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ for (Extension<DownloadScheme> e : downloadSchemes) {
String schemeName = e.getExportName();
DownloadScheme scheme = e.getProvider().get();
if (!scheme.isEnabled()
@@ -1502,7 +1504,7 @@ public class ChangeJson {
String projectName,
String refName,
FetchInfo fetchInfo) {
- for (DynamicMap.Entry<DownloadCommand> e2 : commands) {
+ for (Extension<DownloadCommand> e2 : commands) {
String commandName = e2.getExportName();
DownloadCommand command = e2.getProvider().get();
String c = command.getCommand(scheme, projectName, refName);
diff --git a/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java b/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
index 646d395225..14c93dc0d9 100644
--- a/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
+++ b/java/com/google/gerrit/server/config/CanonicalWebUrlModule.java
@@ -30,6 +30,7 @@ public abstract class CanonicalWebUrlModule extends AbstractModule {
//
final Class<? extends Provider<String>> provider = provider();
bind(String.class).annotatedWith(CanonicalWebUrl.class).toProvider(provider);
+ bind(UrlFormatter.class).to(DefaultBrowseUrls.class);
}
protected abstract Class<? extends Provider<String>> provider();
diff --git a/java/com/google/gerrit/server/config/ChangeCleanupConfig.java b/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
index 632293ef25..f49224780f 100644
--- a/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
+++ b/java/com/google/gerrit/server/config/ChangeCleanupConfig.java
@@ -15,7 +15,6 @@
package com.google.gerrit.server.config;
import com.google.common.base.Strings;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.server.config.ScheduleConfig.Schedule;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -31,7 +30,7 @@ public class ChangeCleanupConfig {
private static String KEY_ABANDON_MESSAGE = "abandonMessage";
private static String DEFAULT_ABANDON_MESSAGE =
"Auto-Abandoned due to inactivity, see "
- + "${URL}Documentation/user-change-cleanup.html#auto-abandon\n"
+ + "${URL}\n"
+ "\n"
+ "If this change is still wanted it should be restored.";
@@ -41,12 +40,11 @@ public class ChangeCleanupConfig {
private final String abandonMessage;
@Inject
- ChangeCleanupConfig(
- @GerritServerConfig Config cfg, @CanonicalWebUrl @Nullable String canonicalWebUrl) {
+ ChangeCleanupConfig(@GerritServerConfig Config cfg, UrlFormatter urlFormatter) {
schedule = ScheduleConfig.createSchedule(cfg, SECTION);
abandonAfter = readAbandonAfter(cfg);
abandonIfMergeable = cfg.getBoolean(SECTION, null, KEY_ABANDON_IF_MERGEABLE, true);
- abandonMessage = readAbandonMessage(cfg, canonicalWebUrl);
+ abandonMessage = readAbandonMessage(cfg, urlFormatter);
}
private long readAbandonAfter(Config cfg) {
@@ -55,14 +53,17 @@ public class ChangeCleanupConfig {
return abandonAfter >= 0 ? abandonAfter : 0;
}
- private String readAbandonMessage(Config cfg, String webUrl) {
+ private String readAbandonMessage(Config cfg, UrlFormatter urlFormatter) {
String abandonMessage = cfg.getString(SECTION, null, KEY_ABANDON_MESSAGE);
if (Strings.isNullOrEmpty(abandonMessage)) {
abandonMessage = DEFAULT_ABANDON_MESSAGE;
}
- if (!Strings.isNullOrEmpty(webUrl)) {
- abandonMessage = abandonMessage.replaceAll("\\$\\{URL\\}", webUrl);
+
+ String docUrl = urlFormatter.getDocUrl("user-change-cleanup.html", "auto-abandon").orElse("");
+ if (!docUrl.isEmpty()) {
+ abandonMessage = abandonMessage.replaceAll("\\$\\{URL\\}", docUrl);
}
+
return abandonMessage;
}
diff --git a/java/com/google/gerrit/extensions/registration/NamedProvider.java b/java/com/google/gerrit/server/config/DefaultBrowseUrls.java
index aca651b5f8..988cb0551b 100644
--- a/java/com/google/gerrit/extensions/registration/NamedProvider.java
+++ b/java/com/google/gerrit/server/config/DefaultBrowseUrls.java
@@ -12,17 +12,24 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package com.google.gerrit.extensions.registration;
+package com.google.gerrit.server.config;
-import com.google.inject.Provider;
+import java.util.Optional;
+import javax.inject.Inject;
+import javax.inject.Provider;
+import javax.inject.Singleton;
-/** Pair of provider implementation and plugin providing it. */
-class NamedProvider<T> {
- final Provider<T> impl;
- final String pluginName;
+@Singleton
+public class DefaultBrowseUrls implements UrlFormatter {
+ private final Provider<String> canonicalWebUrlProvider;
- NamedProvider(Provider<T> provider, String pluginName) {
- this.impl = provider;
- this.pluginName = pluginName;
+ @Inject
+ DefaultBrowseUrls(@CanonicalWebUrl Provider<String> canonicalWebUrlProvider) {
+ this.canonicalWebUrlProvider = canonicalWebUrlProvider;
+ }
+
+ @Override
+ public Optional<String> getWebUrl() {
+ return Optional.ofNullable(canonicalWebUrlProvider.get());
}
}
diff --git a/java/com/google/gerrit/server/config/ProjectConfigEntry.java b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
index d30e080aef..5515f0ebc3 100644
--- a/java/com/google/gerrit/server/config/ProjectConfigEntry.java
+++ b/java/com/google/gerrit/server/config/ProjectConfigEntry.java
@@ -22,7 +22,7 @@ import com.google.gerrit.extensions.api.projects.ConfigValue;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicMap.Entry;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -321,7 +321,7 @@ public class ProjectConfigEntry {
ProjectConfig oldCfg = parseConfig(p, event.getOldObjectId());
ProjectConfig newCfg = parseConfig(p, event.getNewObjectId());
if (oldCfg != null && newCfg != null) {
- for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
+ for (Extension<ProjectConfigEntry> e : pluginConfigEntries) {
ProjectConfigEntry configEntry = e.getProvider().get();
String newValue = getValue(newCfg, e);
String oldValue = getValue(oldCfg, e);
@@ -367,7 +367,7 @@ public class ProjectConfigEntry {
}
}
- private static String getValue(ProjectConfig cfg, Entry<ProjectConfigEntry> e) {
+ private static String getValue(ProjectConfig cfg, Extension<ProjectConfigEntry> e) {
String value = cfg.getPluginConfig(e.getPluginName()).getString(e.getExportName());
if (value == null) {
value = e.getProvider().get().getDefaultValue();
diff --git a/java/com/google/gerrit/server/config/UrlFormatter.java b/java/com/google/gerrit/server/config/UrlFormatter.java
new file mode 100644
index 0000000000..5cec1ac2c4
--- /dev/null
+++ b/java/com/google/gerrit/server/config/UrlFormatter.java
@@ -0,0 +1,66 @@
+// 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.config;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.reviewdb.client.Project;
+import java.util.Optional;
+
+/**
+ * Formats URLs to different parts of the Gerrit API and UI.
+ *
+ * <p>By default, these gerrit URLs are formed by adding suffixes to the web URL. The interface
+ * centralizes these conventions, and also allows introducing different, custom URL schemes.
+ *
+ * <p>Unfortunately, Gerrit operates in modes for which there is no canonical URL. This can be in
+ * standalone utilities that have no HTTP server (eg. index upgrade commands), in servers that run
+ * SSH only, or in a HTTP/SSH server that is accessed over SSH without canonical web URL configured.
+ */
+public interface UrlFormatter {
+
+ /**
+ * The canonical base URL where this Gerrit installation can be reached.
+ *
+ * <p>For the default implementations below to work, it must end in "/".
+ */
+ Optional<String> getWebUrl();
+
+ /** Returns the URL for viewing a change. */
+ default Optional<String> getChangeViewUrl(@Nullable Project.NameKey project, Change.Id id) {
+
+ // In the PolyGerrit URL (contrary to REST URLs) there is no need to URL-escape strings, since
+ // the /+/ separator unambiguously defines how to parse the path.
+ return getWebUrl()
+ .map(url -> url + "c/" + (project != null ? project.get() + "/+/" : "") + id.get());
+ }
+
+ /** Returns a URL pointing to a section of the settings page. */
+ default Optional<String> getSettingsUrl(String section) {
+ return getWebUrl()
+ .map(url -> url + "settings" + (Strings.isNullOrEmpty(section) ? "" : "#" + section));
+ }
+
+ /** Returns a URL pointing to a documentation page, at a given named anchor. */
+ default Optional<String> getDocUrl(String page, String anchor) {
+ return getWebUrl().map(url -> url + "Documentation/" + page + "#" + anchor);
+ }
+
+ /** Returns a REST API URL for a given suffix (eg. "accounts/self/details") */
+ default Optional<String> getRestUrl(String suffix) {
+ return getWebUrl().map(url -> url + suffix);
+ }
+}
diff --git a/java/com/google/gerrit/server/edit/ChangeEditJson.java b/java/com/google/gerrit/server/edit/ChangeEditJson.java
index 78baef7195..bd9c3a616b 100644
--- a/java/com/google/gerrit/server/edit/ChangeEditJson.java
+++ b/java/com/google/gerrit/server/edit/ChangeEditJson.java
@@ -20,6 +20,7 @@ import com.google.gerrit.extensions.common.FetchInfo;
import com.google.gerrit.extensions.config.DownloadCommand;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.server.CommonConverters;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.change.ChangeJson;
@@ -78,7 +79,7 @@ public class ChangeEditJson {
private Map<String, FetchInfo> fillFetchMap(ChangeEdit edit) {
Map<String, FetchInfo> r = new LinkedHashMap<>();
- for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ for (Extension<DownloadScheme> e : downloadSchemes) {
String schemeName = e.getExportName();
DownloadScheme scheme = e.getProvider().get();
if (!scheme.isEnabled()
diff --git a/java/com/google/gerrit/server/events/EventFactory.java b/java/com/google/gerrit/server/events/EventFactory.java
index fbce4b273f..62dc511b68 100644
--- a/java/com/google/gerrit/server/events/EventFactory.java
+++ b/java/com/google/gerrit/server/events/EventFactory.java
@@ -20,7 +20,6 @@ import static java.util.Comparator.comparing;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.LabelTypes;
import com.google.gerrit.common.data.SubmitRecord;
@@ -42,7 +41,7 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.change.ChangeKindCache;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.data.AccountAttribute;
import com.google.gerrit.server.data.ApprovalAttribute;
import com.google.gerrit.server.data.ChangeAttribute;
@@ -86,8 +85,8 @@ public class EventFactory {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final AccountCache accountCache;
+ private final UrlFormatter urlFormatter;
private final Emails emails;
- private final Provider<String> urlProvider;
private final PatchListCache patchListCache;
private final Provider<PersonIdent> myIdent;
private final ChangeData.Factory changeDataFactory;
@@ -101,7 +100,7 @@ public class EventFactory {
EventFactory(
AccountCache accountCache,
Emails emails,
- @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+ UrlFormatter urlFormatter,
PatchListCache patchListCache,
@GerritPersonIdent Provider<PersonIdent> myIdent,
ChangeData.Factory changeDataFactory,
@@ -111,8 +110,8 @@ public class EventFactory {
SchemaFactory<ReviewDb> schema,
IndexConfig indexConfig) {
this.accountCache = accountCache;
+ this.urlFormatter = urlFormatter;
this.emails = emails;
- this.urlProvider = urlProvider;
this.patchListCache = patchListCache;
this.myIdent = myIdent;
this.changeDataFactory = changeDataFactory;
@@ -678,11 +677,8 @@ public class EventFactory {
/** Get a link to the change; null if the server doesn't know its own address. */
private String getChangeUrl(Change change) {
- if (change != null && urlProvider.get() != null) {
- StringBuilder r = new StringBuilder();
- r.append(urlProvider.get());
- r.append(change.getChangeId());
- return r.toString();
+ if (change != null) {
+ return urlFormatter.getChangeViewUrl(change.getProject(), change.getId()).orElse(null);
}
return null;
}
diff --git a/java/com/google/gerrit/server/extensions/webui/UiActions.java b/java/com/google/gerrit/server/extensions/webui/UiActions.java
index af28bed3fe..3ca2bdb93d 100644
--- a/java/com/google/gerrit/server/extensions/webui/UiActions.java
+++ b/java/com/google/gerrit/server/extensions/webui/UiActions.java
@@ -26,6 +26,7 @@ import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.access.GlobalOrPluginPermission;
import com.google.gerrit.extensions.conditions.BooleanCondition;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.registration.PluginName;
import com.google.gerrit.extensions.restapi.RestCollection;
import com.google.gerrit.extensions.restapi.RestResource;
@@ -121,7 +122,7 @@ public class UiActions {
@Nullable
private <R extends RestResource> UiAction.Description describe(
- DynamicMap.Entry<RestView<R>> e, R resource) {
+ Extension<RestView<R>> e, R resource) {
int d = e.getExportName().indexOf('.');
if (d < 0) {
return null;
diff --git a/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java b/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
index 513d909551..7cf97ac779 100644
--- a/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
+++ b/java/com/google/gerrit/server/git/DefaultChangeReportFormatter.java
@@ -14,9 +14,11 @@
package com.google.gerrit.server.git;
+import com.google.common.base.Preconditions;
import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.inject.Inject;
+import java.util.Optional;
/** Print a change description for use in git command-line progress. */
public class DefaultChangeReportFormatter implements ChangeReportFormatter {
@@ -24,30 +26,29 @@ public class DefaultChangeReportFormatter implements ChangeReportFormatter {
private static final String SUBJECT_CROP_APPENDIX = "...";
private static final int SUBJECT_CROP_RANGE = 10;
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
@Inject
- DefaultChangeReportFormatter(@CanonicalWebUrl String canonicalWebUrl) {
- this.canonicalWebUrl = canonicalWebUrl;
+ DefaultChangeReportFormatter(UrlFormatter urlFormatter) {
+ this.urlFormatter = urlFormatter;
}
@Override
public String newChange(ChangeReportFormatter.Input input) {
- return formatChangeUrl(canonicalWebUrl, input);
+ return formatChangeUrl(input);
}
@Override
public String changeUpdated(ChangeReportFormatter.Input input) {
- return formatChangeUrl(canonicalWebUrl, input);
- }
-
- public static String formatChangeUrl(String canonicalWebUrl, Change change) {
- return canonicalWebUrl + "c/" + change.getProject().get() + "/+/" + change.getChangeId();
+ return formatChangeUrl(input);
}
@Override
public String changeClosed(ChangeReportFormatter.Input input) {
- return String.format("change %s closed", formatChangeUrl(canonicalWebUrl, input.change()));
+ Change c = input.change();
+ return String.format(
+ "change %s closed",
+ urlFormatter.getChangeViewUrl(c.getProject(), c.getId()).orElse(c.getId().toString()));
}
protected String cropSubject(String subject) {
@@ -65,11 +66,15 @@ public class DefaultChangeReportFormatter implements ChangeReportFormatter {
return subject;
}
- protected String formatChangeUrl(String url, Input input) {
+ protected String formatChangeUrl(Input input) {
+ Change c = input.change();
+ Optional<String> changeUrl = urlFormatter.getChangeViewUrl(c.getProject(), c.getId());
+ Preconditions.checkState(changeUrl.isPresent());
+
StringBuilder m =
new StringBuilder()
.append(" ")
- .append(formatChangeUrl(url, input.change()))
+ .append(changeUrl.get())
.append(" ")
.append(cropSubject(input.subject()));
if (input.isEdit()) {
diff --git a/java/com/google/gerrit/server/git/MergeUtil.java b/java/com/google/gerrit/server/git/MergeUtil.java
index c035269536..c2e147b317 100644
--- a/java/com/google/gerrit/server/git/MergeUtil.java
+++ b/java/com/google/gerrit/server/git/MergeUtil.java
@@ -25,7 +25,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.FooterConstants;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -42,8 +41,8 @@ import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.project.ProjectState;
@@ -65,6 +64,7 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import org.eclipse.jgit.errors.AmbiguousObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -147,7 +147,7 @@ public class MergeUtil {
private final Provider<ReviewDb> db;
private final IdentifiedUser.GenericFactory identifiedUserFactory;
- private final Provider<String> urlProvider;
+ private final UrlFormatter urlFormatter;
private final ApprovalsUtil approvalsUtil;
private final ProjectState project;
private final boolean useContentMerge;
@@ -159,7 +159,7 @@ public class MergeUtil {
@GerritServerConfig Config serverConfig,
Provider<ReviewDb> db,
IdentifiedUser.GenericFactory identifiedUserFactory,
- @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+ UrlFormatter urlFormatter,
ApprovalsUtil approvalsUtil,
PluggableCommitMessageGenerator commitMessageGenerator,
@Assisted ProjectState project) {
@@ -167,7 +167,7 @@ public class MergeUtil {
serverConfig,
db,
identifiedUserFactory,
- urlProvider,
+ urlFormatter,
approvalsUtil,
project,
commitMessageGenerator,
@@ -179,14 +179,14 @@ public class MergeUtil {
@GerritServerConfig Config serverConfig,
Provider<ReviewDb> db,
IdentifiedUser.GenericFactory identifiedUserFactory,
- @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+ UrlFormatter urlFormatter,
ApprovalsUtil approvalsUtil,
@Assisted ProjectState project,
PluggableCommitMessageGenerator commitMessageGenerator,
@Assisted boolean useContentMerge) {
this.db = db;
this.identifiedUserFactory = identifiedUserFactory;
- this.urlProvider = urlProvider;
+ this.urlFormatter = urlFormatter;
this.approvalsUtil = approvalsUtil;
this.project = project;
this.useContentMerge = useContentMerge;
@@ -345,17 +345,16 @@ public class MergeUtil {
msgbuf.append('\n');
}
- final String siteUrl = urlProvider.get();
- if (siteUrl != null) {
- final String url = siteUrl + c.getId().get();
- if (!contains(footers, FooterConstants.REVIEWED_ON, url)) {
- msgbuf.append(FooterConstants.REVIEWED_ON.getName());
- msgbuf.append(": ");
- msgbuf.append(url);
- msgbuf.append('\n');
+ Optional<String> url = urlFormatter.getChangeViewUrl(null, c.getId());
+ if (url.isPresent()) {
+ if (!contains(footers, FooterConstants.REVIEWED_ON, url.get())) {
+ msgbuf
+ .append(FooterConstants.REVIEWED_ON.getName())
+ .append(": ")
+ .append(url.get())
+ .append('\n');
}
}
-
PatchSetApproval submitAudit = null;
for (PatchSetApproval a : safeGetApprovals(notes, psId)) {
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index eb62d547aa..b9ab6fda46 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -110,14 +110,9 @@ public class AsyncReceiveCommits implements PreReceiveHook {
final MultiProgressMonitor progress;
private final Collection<ReceiveCommand> commands;
- private final ReceiveCommits receiveCommits;
private Worker(Collection<ReceiveCommand> commands) {
this.commands = commands;
- receiveCommits =
- factory.create(
- projectState, user, receivePack, allRefsWatcher, extraReviewers, messageSender);
- receiveCommits.init();
progress = new MultiProgressMonitor(new MessageSenderOutputStream(), "Processing changes");
}
@@ -173,7 +168,7 @@ public class AsyncReceiveCommits implements PreReceiveHook {
}
}
- private final ReceiveCommits.Factory factory;
+ private final ReceiveCommits receiveCommits;
private final PermissionBackend.ForProject perm;
private final ReceivePack receivePack;
private final ExecutorService executor;
@@ -184,8 +179,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
private final ProjectState projectState;
private final IdentifiedUser user;
private final Repository repo;
- private final MessageSender messageSender;
- private final SetMultimap<ReviewerStateInternal, Account.Id> extraReviewers;
private final AllRefsWatcher allRefsWatcher;
@Inject
@@ -206,7 +199,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
@Assisted @Nullable MessageSender messageSender,
@Assisted SetMultimap<ReviewerStateInternal, Account.Id> extraReviewers)
throws PermissionBackendException {
- this.factory = factory;
this.executor = executor;
this.scopePropagator = scopePropagator;
this.receiveConfig = receiveConfig;
@@ -215,8 +207,6 @@ public class AsyncReceiveCommits implements PreReceiveHook {
this.projectState = projectState;
this.user = user;
this.repo = repo;
- this.messageSender = messageSender;
- this.extraReviewers = extraReviewers;
Project.NameKey projectName = projectState.getNameKey();
receivePack = new ReceivePack(repo);
@@ -251,6 +241,11 @@ public class AsyncReceiveCommits implements PreReceiveHook {
advHooks.add(new ReceiveCommitsAdvertiseRefsHook(queryProvider, projectName));
advHooks.add(new HackPushNegotiateHook());
receivePack.setAdvertiseRefsHook(AdvertiseRefsHookChain.newChain(advHooks));
+
+ receiveCommits =
+ factory.create(
+ projectState, user, receivePack, allRefsWatcher, extraReviewers, messageSender);
+ receiveCommits.init();
}
/** Determine if the user can upload commits. */
@@ -275,6 +270,11 @@ public class AsyncReceiveCommits implements PreReceiveHook {
@Override
public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> commands) {
+ if (commands.stream().anyMatch(c -> c.getResult() != Result.NOT_ATTEMPTED)) {
+ // Stop processing when command was already processed by previously invoked
+ // pre-receive hooks
+ return;
+ }
Worker w = new Worker(commands);
try {
w.progress.waitFor(
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index 7566b5593c..ef699b32a4 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -70,8 +70,8 @@ import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicMap.Entry;
import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -1131,7 +1131,7 @@ class ReceiveCommits {
* fails.
*/
private void validatePluginConfig(ReceiveCommand cmd, ProjectConfig cfg) {
- for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
+ for (Extension<ProjectConfigEntry> e : pluginConfigEntries) {
PluginConfig pluginCfg = cfg.getPluginConfig(e.getPluginName());
ProjectConfigEntry configEntry = e.getProvider().get();
String value = pluginCfg.getString(e.getExportName());
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 7930fe89e2..8af04e0f4b 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -20,13 +20,13 @@ import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
import static java.util.stream.Collectors.toList;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.Nullable;
-import com.google.gerrit.common.PageLinks;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -41,8 +41,8 @@ import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.externalids.ExternalIdsConsistencyChecker;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AllUsersName;
-import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.ValidationError;
@@ -63,6 +63,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Optional;
import java.util.regex.Pattern;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
@@ -87,7 +88,7 @@ public class CommitValidators {
@Singleton
public static class Factory {
private final PersonIdent gerritIdent;
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
private final DynamicSet<CommitValidationListener> pluginValidators;
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
@@ -100,7 +101,7 @@ public class CommitValidators {
@Inject
Factory(
@GerritPersonIdent PersonIdent gerritIdent,
- @CanonicalWebUrl @Nullable String canonicalWebUrl,
+ UrlFormatter urlFormatter,
@GerritServerConfig Config cfg,
DynamicSet<CommitValidationListener> pluginValidators,
GitRepositoryManager repoManager,
@@ -110,7 +111,7 @@ public class CommitValidators {
AccountValidator accountValidator,
ProjectCache projectCache) {
this.gerritIdent = gerritIdent;
- this.canonicalWebUrl = canonicalWebUrl;
+ this.urlFormatter = urlFormatter;
this.pluginValidators = pluginValidators;
this.repoManager = repoManager;
this.allUsers = allUsers;
@@ -138,16 +139,11 @@ public class CommitValidators {
new UploadMergesPermissionValidator(perm),
new ProjectStateValidationListener(projectState),
new AmendedGerritMergeCommitValidationListener(perm, gerritIdent),
- new AuthorUploaderValidator(user, perm, canonicalWebUrl),
- new CommitterUploaderValidator(user, perm, canonicalWebUrl),
+ new AuthorUploaderValidator(user, perm, urlFormatter),
+ new CommitterUploaderValidator(user, perm, urlFormatter),
new SignedOffByValidator(user, perm, projectState),
new ChangeIdValidator(
- projectState,
- user,
- canonicalWebUrl,
- installCommitMsgHookCommand,
- sshInfo,
- change),
+ projectState, user, urlFormatter, installCommitMsgHookCommand, sshInfo, change),
new ConfigValidator(branch, user, rw, allUsers, allProjects),
new BannedCommitsValidator(rejectCommits),
new PluginCommitValidationListener(pluginValidators),
@@ -171,15 +167,10 @@ public class CommitValidators {
new UploadMergesPermissionValidator(perm),
new ProjectStateValidationListener(projectState),
new AmendedGerritMergeCommitValidationListener(perm, gerritIdent),
- new AuthorUploaderValidator(user, perm, canonicalWebUrl),
+ new AuthorUploaderValidator(user, perm, urlFormatter),
new SignedOffByValidator(user, perm, projectCache.checkedGet(branch.getParentKey())),
new ChangeIdValidator(
- projectState,
- user,
- canonicalWebUrl,
- installCommitMsgHookCommand,
- sshInfo,
- change),
+ projectState, user, urlFormatter, installCommitMsgHookCommand, sshInfo, change),
new ConfigValidator(branch, user, rw, allUsers, allProjects),
new PluginCommitValidationListener(pluginValidators),
new ExternalIdUpdateListener(allUsers, externalIdsConsistencyChecker),
@@ -208,8 +199,8 @@ public class CommitValidators {
ImmutableList.of(
new UploadMergesPermissionValidator(perm),
new ProjectStateValidationListener(projectCache.checkedGet(branch.getParentKey())),
- new AuthorUploaderValidator(user, perm, canonicalWebUrl),
- new CommitterUploaderValidator(user, perm, canonicalWebUrl)));
+ new AuthorUploaderValidator(user, perm, urlFormatter),
+ new CommitterUploaderValidator(user, perm, urlFormatter)));
}
}
@@ -253,7 +244,7 @@ public class CommitValidators {
private static final Pattern CHANGE_ID = Pattern.compile(CHANGE_ID_PATTERN);
private final ProjectState projectState;
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
private final String installCommitMsgHookCommand;
private final SshInfo sshInfo;
private final IdentifiedUser user;
@@ -262,12 +253,12 @@ public class CommitValidators {
public ChangeIdValidator(
ProjectState projectState,
IdentifiedUser user,
- String canonicalWebUrl,
+ UrlFormatter urlFormatter,
String installCommitMsgHookCommand,
SshInfo sshInfo,
Change change) {
this.projectState = projectState;
- this.canonicalWebUrl = canonicalWebUrl;
+ this.urlFormatter = urlFormatter;
this.installCommitMsgHookCommand = installCommitMsgHookCommand;
this.sshInfo = sshInfo;
this.user = user;
@@ -352,10 +343,12 @@ public class CommitValidators {
// If there are no SSH keys, the commit-msg hook must be installed via
// HTTP(S)
+ Optional<String> webUrl = urlFormatter.getWebUrl();
if (hostKeys.isEmpty()) {
+ Preconditions.checkState(webUrl.isPresent());
return String.format(
" f=\"$(git rev-parse --git-dir)/hooks/commit-msg\"; curl -o \"$f\" %stools/hooks/commit-msg ; chmod +x \"$f\"",
- canonicalWebUrl);
+ webUrl.get());
}
// SSH keys exist, so the hook can be installed with scp.
@@ -365,7 +358,8 @@ public class CommitValidators {
int c = host.lastIndexOf(':');
if (0 <= c) {
if (host.startsWith("*:")) {
- sshHost = getGerritHost(canonicalWebUrl);
+ Preconditions.checkState(webUrl.isPresent());
+ sshHost = getGerritHost(webUrl.get());
} else {
sshHost = host.substring(0, c);
}
@@ -547,13 +541,13 @@ public class CommitValidators {
public static class AuthorUploaderValidator implements CommitValidationListener {
private final IdentifiedUser user;
private final PermissionBackend.ForRef perm;
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
public AuthorUploaderValidator(
- IdentifiedUser user, PermissionBackend.ForRef perm, String canonicalWebUrl) {
+ IdentifiedUser user, PermissionBackend.ForRef perm, UrlFormatter urlFormatter) {
this.user = user;
this.perm = perm;
- this.canonicalWebUrl = canonicalWebUrl;
+ this.urlFormatter = urlFormatter;
}
@Override
@@ -568,7 +562,7 @@ public class CommitValidators {
return Collections.emptyList();
} catch (AuthException e) {
throw new CommitValidationException(
- "invalid author", invalidEmail("author", author, user, canonicalWebUrl));
+ "invalid author", invalidEmail("author", author, user, urlFormatter));
} catch (PermissionBackendException e) {
logger.atSevere().withCause(e).log("cannot check FORGE_AUTHOR");
throw new CommitValidationException("internal auth error");
@@ -580,13 +574,13 @@ public class CommitValidators {
public static class CommitterUploaderValidator implements CommitValidationListener {
private final IdentifiedUser user;
private final PermissionBackend.ForRef perm;
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
public CommitterUploaderValidator(
- IdentifiedUser user, PermissionBackend.ForRef perm, String canonicalWebUrl) {
+ IdentifiedUser user, PermissionBackend.ForRef perm, UrlFormatter urlFormatter) {
this.user = user;
this.perm = perm;
- this.canonicalWebUrl = canonicalWebUrl;
+ this.urlFormatter = urlFormatter;
}
@Override
@@ -601,7 +595,7 @@ public class CommitValidators {
return Collections.emptyList();
} catch (AuthException e) {
throw new CommitValidationException(
- "invalid committer", invalidEmail("committer", committer, user, canonicalWebUrl));
+ "invalid committer", invalidEmail("committer", committer, user, urlFormatter));
} catch (PermissionBackendException e) {
logger.atSevere().withCause(e).log("cannot check FORGE_COMMITTER");
throw new CommitValidationException("internal auth error");
@@ -821,7 +815,7 @@ public class CommitValidators {
}
private static CommitValidationMessage invalidEmail(
- String type, PersonIdent who, IdentifiedUser currentUser, String canonicalWebUrl) {
+ String type, PersonIdent who, IdentifiedUser currentUser, UrlFormatter urlFormatter) {
StringBuilder sb = new StringBuilder();
sb.append("email address ")
@@ -839,11 +833,11 @@ public class CommitValidators {
}
}
- if (canonicalWebUrl != null) {
- sb.append("To register an email address, visit:\n");
- sb.append(canonicalWebUrl).append("#").append(PageLinks.SETTINGS_CONTACT).append("\n");
+ if (urlFormatter.getSettingsUrl("").isPresent()) {
+ sb.append("To register an email address, visit:\n")
+ .append(urlFormatter.getSettingsUrl("EmailAddresses").get())
+ .append("\n\n");
}
- sb.append("\n");
return new CommitValidationMessage(sb.toString(), true);
}
diff --git a/java/com/google/gerrit/server/git/validators/MergeValidators.java b/java/com/google/gerrit/server/git/validators/MergeValidators.java
index c4df4dd11c..f755aab162 100644
--- a/java/com/google/gerrit/server/git/validators/MergeValidators.java
+++ b/java/com/google/gerrit/server/git/validators/MergeValidators.java
@@ -19,8 +19,8 @@ import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicMap.Entry;
import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
@@ -207,7 +207,7 @@ public class MergeValidators {
}
}
- for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
+ for (Extension<ProjectConfigEntry> e : pluginConfigEntries) {
PluginConfig pluginCfg = cfg.getPluginConfig(e.getPluginName());
ProjectConfigEntry configEntry = e.getProvider().get();
diff --git a/java/com/google/gerrit/server/logging/TraceContext.java b/java/com/google/gerrit/server/logging/TraceContext.java
index 977baa585d..d68874039b 100644
--- a/java/com/google/gerrit/server/logging/TraceContext.java
+++ b/java/com/google/gerrit/server/logging/TraceContext.java
@@ -192,6 +192,21 @@ public class TraceContext implements AutoCloseable {
return new TraceTimer(format, arg1, arg2);
}
+ /**
+ * Opens a new timer that logs the time for an operation if request tracing is enabled.
+ *
+ * <p>If request tracing is not enabled this is a no-op.
+ *
+ * @param format the message format string
+ * @param arg1 first argument for the message
+ * @param arg2 second argument for the message
+ * @param arg3 third argument for the message
+ * @return the trace timer
+ */
+ public static TraceTimer newTimer(String format, Object arg1, Object arg2, Object arg3) {
+ return new TraceTimer(format, arg1, arg2, arg3);
+ }
+
public static class TraceTimer implements AutoCloseable {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@@ -210,6 +225,11 @@ public class TraceContext implements AutoCloseable {
this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg1, arg2, elapsedMs));
}
+ private TraceTimer(
+ String format, @Nullable Object arg1, @Nullable Object arg2, @Nullable Object arg3) {
+ this(elapsedMs -> logger.atFine().log(format + " (%d ms)", arg1, arg2, arg3, elapsedMs));
+ }
+
private TraceTimer(Consumer<Long> logFn) {
this.logFn = logFn;
this.stopwatch = Stopwatch.createStarted();
diff --git a/java/com/google/gerrit/server/mail/receive/MailProcessor.java b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
index ec0c1f2e23..262e82bc5c 100644
--- a/java/com/google/gerrit/server/mail/receive/MailProcessor.java
+++ b/java/com/google/gerrit/server/mail/receive/MailProcessor.java
@@ -23,6 +23,7 @@ import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.client.Side;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.mail.HtmlParser;
@@ -46,7 +47,7 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.account.Emails;
import com.google.gerrit.server.change.EmailReviewComments;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.extensions.events.CommentAdded;
import com.google.gerrit.server.mail.MailFilter;
import com.google.gerrit.server.mail.send.InboundEmailRejectionSender;
@@ -97,7 +98,7 @@ public class MailProcessor {
private final CommentAdded commentAdded;
private final ApprovalsUtil approvalsUtil;
private final AccountCache accountCache;
- private final Provider<String> canonicalUrl;
+ private final UrlFormatter urlFormatter;
@Inject
public MailProcessor(
@@ -115,7 +116,7 @@ public class MailProcessor {
ApprovalsUtil approvalsUtil,
CommentAdded commentAdded,
AccountCache accountCache,
- @CanonicalWebUrl Provider<String> canonicalUrl) {
+ UrlFormatter urlFormatter) {
this.emails = emails;
this.emailRejectionSender = emailRejectionSender;
this.retryHelper = retryHelper;
@@ -130,7 +131,7 @@ public class MailProcessor {
this.commentAdded = commentAdded;
this.approvalsUtil = approvalsUtil;
this.accountCache = accountCache;
- this.canonicalUrl = canonicalUrl;
+ this.urlFormatter = urlFormatter;
}
/**
@@ -148,7 +149,7 @@ public class MailProcessor {
private void processImpl(BatchUpdate.Factory buf, MailMessage message)
throws OrmException, UpdateException, RestApiException, IOException {
- for (DynamicMap.Entry<MailFilter> filter : mailFilters) {
+ for (Extension<MailFilter> filter : mailFilters) {
if (!filter.getProvider().get().shouldProcessMessage(message)) {
logger.atWarning().log(
"Message %s filtered by plugin %s %s. Will delete message.",
@@ -237,7 +238,11 @@ public class MailProcessor {
.sorted(CommentsUtil.COMMENT_ORDER)
.collect(toList());
Project.NameKey project = cd.project();
- String changeUrl = canonicalUrl.get() + "c/" + cd.project().get() + "/+/" + cd.getId().get();
+
+ // If URL is not defined, we won't be able to parse line comments. We still attempt to get the
+ // other ones.
+ String changeUrl =
+ urlFormatter.getChangeViewUrl(cd.project(), cd.getId()).orElse("http://gerrit.invalid/");
List<MailComment> parsedComments;
if (useHtmlParser(message)) {
diff --git a/java/com/google/gerrit/server/mail/send/ChangeEmail.java b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
index bfb210ec9c..0b8a3c1192 100644
--- a/java/com/google/gerrit/server/mail/send/ChangeEmail.java
+++ b/java/com/google/gerrit/server/mail/send/ChangeEmail.java
@@ -17,6 +17,7 @@ package com.google.gerrit.server.mail.send;
import com.google.common.base.Splitter;
import com.google.common.collect.ListMultimap;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.api.changes.RecipientType;
@@ -217,11 +218,9 @@ public abstract class ChangeEmail extends NotificationEmail {
}
/** Get a link to the change; null if the server doesn't know its own address. */
+ @Nullable
public String getChangeUrl() {
- if (getGerritUrl() != null) {
- return getGerritUrl() + "c/" + change.getProject().get() + "/+/" + change.getChangeId();
- }
- return null;
+ return args.urlFormatter.getChangeViewUrl(change.getProject(), change.getId()).orElse(null);
}
public String getChangeMessageThreadId() {
diff --git a/java/com/google/gerrit/server/mail/send/EmailArguments.java b/java/com/google/gerrit/server/mail/send/EmailArguments.java
index f49951fd4b..42d1b32d89 100644
--- a/java/com/google/gerrit/server/mail/send/EmailArguments.java
+++ b/java/com/google/gerrit/server/mail/send/EmailArguments.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.mail.send;
-import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.AnonymousUser;
@@ -27,10 +26,10 @@ import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.GroupBackend;
import com.google.gerrit.server.config.AllProjectsName;
import com.google.gerrit.server.config.AnonymousCowardName;
-import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritInstanceName;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.mail.EmailSettings;
import com.google.gerrit.server.notedb.ChangeNotes;
@@ -67,7 +66,7 @@ public class EmailArguments {
final AnonymousUser anonymousUser;
final String anonymousCowardName;
final PersonIdent gerritPersonIdent;
- final Provider<String> urlProvider;
+ final UrlFormatter urlFormatter;
final AllProjectsName allProjectsName;
final List<String> sshAddresses;
final SitePaths site;
@@ -100,7 +99,7 @@ public class EmailArguments {
AnonymousUser anonymousUser,
@AnonymousCowardName String anonymousCowardName,
GerritPersonIdentProvider gerritPersonIdentProvider,
- @CanonicalWebUrl @Nullable Provider<String> urlProvider,
+ UrlFormatter urlFormatter,
AllProjectsName allProjectsName,
ChangeQueryBuilder queryBuilder,
Provider<ReviewDb> db,
@@ -129,7 +128,7 @@ public class EmailArguments {
this.anonymousUser = anonymousUser;
this.anonymousCowardName = anonymousCowardName;
this.gerritPersonIdent = gerritPersonIdentProvider.get();
- this.urlProvider = urlProvider;
+ this.urlFormatter = urlFormatter;
this.allProjectsName = allProjectsName;
this.queryBuilder = queryBuilder;
this.db = db;
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index fe9b44626a..6182826c66 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -299,7 +299,7 @@ public abstract class OutgoingEmail {
}
public String getGerritUrl() {
- return args.urlProvider.get();
+ return args.urlFormatter.getWebUrl().orElse(null);
}
/** Set a header in the outgoing message. */
diff --git a/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java b/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
index c3c76de228..fc342db677 100644
--- a/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
+++ b/java/com/google/gerrit/server/project/ContributorAgreementsChecker.java
@@ -14,8 +14,6 @@
package com.google.gerrit.server.project;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.common.data.PermissionRule;
import com.google.gerrit.common.data.PermissionRule.Action;
@@ -29,7 +27,7 @@ import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -40,7 +38,7 @@ import java.util.List;
@Singleton
public class ContributorAgreementsChecker {
- private final String canonicalWebUrl;
+ private final UrlFormatter urlFormatter;
private final ProjectCache projectCache;
private final Metrics metrics;
@@ -59,10 +57,8 @@ public class ContributorAgreementsChecker {
@Inject
ContributorAgreementsChecker(
- @CanonicalWebUrl @Nullable String canonicalWebUrl,
- ProjectCache projectCache,
- Metrics metrics) {
- this.canonicalWebUrl = canonicalWebUrl;
+ UrlFormatter urlFormatter, ProjectCache projectCache, Metrics metrics) {
+ this.urlFormatter = urlFormatter;
this.projectCache = projectCache;
this.metrics = metrics;
}
@@ -113,15 +109,8 @@ public class ContributorAgreementsChecker {
.append(" (id=")
.append(iUser.getAccountId())
.append(")");
- if (canonicalWebUrl != null) {
- msg.append(":\n\n ");
- msg.append(canonicalWebUrl);
- msg.append("#");
- msg.append(PageLinks.SETTINGS_AGREEMENTS);
- msg.append("\n");
- } else {
- msg.append(".");
- }
+
+ msg.append(urlFormatter.getSettingsUrl("Agreements").orElse(""));
throw new AuthException(msg.toString());
}
}
diff --git a/java/com/google/gerrit/server/project/CreateProjectArgs.java b/java/com/google/gerrit/server/project/CreateProjectArgs.java
index e4623b227f..a68bd84860 100644
--- a/java/com/google/gerrit/server/project/CreateProjectArgs.java
+++ b/java/com/google/gerrit/server/project/CreateProjectArgs.java
@@ -35,6 +35,8 @@ public class CreateProjectArgs {
public InheritableBoolean newChangeForAllNotInTarget;
public InheritableBoolean changeIdRequired;
public InheritableBoolean rejectEmptyCommit;
+ public InheritableBoolean enableSignedPush;
+ public InheritableBoolean requireSignedPush;
public boolean createEmptyCommit;
public String maxObjectSizeLimit;
@@ -44,6 +46,8 @@ public class CreateProjectArgs {
contentMerge = InheritableBoolean.INHERIT;
changeIdRequired = InheritableBoolean.INHERIT;
newChangeForAllNotInTarget = InheritableBoolean.INHERIT;
+ enableSignedPush = InheritableBoolean.INHERIT;
+ requireSignedPush = InheritableBoolean.INHERIT;
submitType = SubmitType.MERGE_IF_NECESSARY;
}
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 566786984b..2ec2e7ccb3 100644
--- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -31,6 +31,7 @@ import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.errors.NotSignedInException;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.index.IndexConfig;
import com.google.gerrit.index.Schema;
import com.google.gerrit.index.SchemaUtil;
@@ -427,7 +428,7 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
}
private void setupDynamicOperators() {
- for (DynamicMap.Entry<ChangeOperatorFactory> e : args.opFactories) {
+ for (Extension<ChangeOperatorFactory> e : args.opFactories) {
String name = e.getExportName() + "_" + e.getPluginName();
opFactories.put(name, e.getProvider().get());
}
@@ -673,6 +674,21 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData> {
}
@Operator
+ public Predicate<ChangeData> repo(String name) {
+ return project(name);
+ }
+
+ @Operator
+ public Predicate<ChangeData> repos(String name) {
+ return projects(name);
+ }
+
+ @Operator
+ public Predicate<ChangeData> parentrepo(String name) {
+ return parentproject(name);
+ }
+
+ @Operator
public Predicate<ChangeData> branch(String name) {
if (name.startsWith("^")) {
return ref("^" + RefNames.fullName(name.substring(1)));
diff --git a/java/com/google/gerrit/server/restapi/account/SetPreferences.java b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
index fccdabe984..2471689644 100644
--- a/java/com/google/gerrit/server/restapi/account/SetPreferences.java
+++ b/java/com/google/gerrit/server/restapi/account/SetPreferences.java
@@ -18,6 +18,7 @@ import com.google.common.base.Strings;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -83,7 +84,7 @@ public class SetPreferences implements RestModifyView<AccountResource, GeneralPr
return;
}
- for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ for (Extension<DownloadScheme> e : downloadSchemes) {
if (e.getExportName().equals(downloadScheme) && e.getProvider().get().isEnabled()) {
return;
}
diff --git a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
index 6b7a708c1f..ae6e5d1c6d 100644
--- a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
+++ b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
@@ -24,6 +24,7 @@ import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.reviewdb.client.Account;
@@ -130,7 +131,7 @@ public class ReviewerRecommender {
new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
List<Double> weights = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
- for (DynamicMap.Entry<ReviewerSuggestion> plugin : reviewerSuggestionPluginMap) {
+ for (Extension<ReviewerSuggestion> plugin : reviewerSuggestionPluginMap) {
tasks.add(
() ->
plugin
diff --git a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
index d6071d5e93..e1144d5bdd 100644
--- a/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
+++ b/java/com/google/gerrit/server/restapi/config/GetServerInfo.java
@@ -39,6 +39,7 @@ import com.google.gerrit.extensions.config.DownloadScheme;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.extensions.webui.WebUiPlugin;
import com.google.gerrit.server.EnableSignedPush;
@@ -252,7 +253,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
private DownloadInfo getDownloadInfo() {
DownloadInfo info = new DownloadInfo();
info.schemes = new HashMap<>();
- for (DynamicMap.Entry<DownloadScheme> e : downloadSchemes) {
+ for (Extension<DownloadScheme> e : downloadSchemes) {
DownloadScheme scheme = e.getProvider().get();
if (scheme.isEnabled() && scheme.getUrl("${project}") != null) {
info.schemes.put(e.getExportName(), getDownloadSchemeInfo(scheme));
@@ -270,7 +271,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
info.isAuthSupported = toBoolean(scheme.isAuthSupported());
info.commands = new HashMap<>();
- for (DynamicMap.Entry<DownloadCommand> e : downloadCommands) {
+ for (Extension<DownloadCommand> e : downloadCommands) {
String commandName = e.getExportName();
DownloadCommand command = e.getProvider().get();
String c = command.getCommand(scheme, "${project}", "${ref}");
@@ -280,7 +281,7 @@ public class GetServerInfo implements RestReadView<ConfigResource> {
}
info.cloneCommands = new HashMap<>();
- for (DynamicMap.Entry<CloneCommand> e : cloneCommands) {
+ for (Extension<CloneCommand> e : cloneCommands) {
String commandName = e.getExportName();
CloneCommand command = e.getProvider().get();
String c = command.getCommand(scheme, "${project-path}/${project-base-name}");
diff --git a/java/com/google/gerrit/server/restapi/config/ListCaches.java b/java/com/google/gerrit/server/restapi/config/ListCaches.java
index 38664fbc61..f310ed7e71 100644
--- a/java/com/google/gerrit/server/restapi/config/ListCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/ListCaches.java
@@ -26,6 +26,7 @@ import com.google.common.cache.CacheStats;
import com.google.common.collect.Streams;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.server.cache.PersistentCache;
@@ -60,7 +61,7 @@ public class ListCaches implements RestReadView<ConfigResource> {
public Map<String, CacheInfo> getCacheInfos() {
Map<String, CacheInfo> cacheInfos = new TreeMap<>();
- for (DynamicMap.Entry<Cache<?, ?>> e : cacheMap) {
+ for (Extension<Cache<?, ?>> e : cacheMap) {
cacheInfos.put(
cacheNameOf(e.getPluginName(), e.getExportName()), new CacheInfo(e.getProvider().get()));
}
diff --git a/java/com/google/gerrit/server/restapi/config/PostCaches.java b/java/com/google/gerrit/server/restapi/config/PostCaches.java
index 57ba097f9f..c633af0ce5 100644
--- a/java/com/google/gerrit/server/restapi/config/PostCaches.java
+++ b/java/com/google/gerrit/server/restapi/config/PostCaches.java
@@ -20,6 +20,7 @@ import static com.google.gerrit.common.data.GlobalCapability.MAINTAIN_SERVER;
import com.google.common.cache.Cache;
import com.google.gerrit.extensions.annotations.RequiresAnyCapability;
import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.registration.PluginName;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -96,7 +97,7 @@ public class PostCaches implements RestCollectionModifyView<ConfigResource, Cach
}
private void flushAll() throws AuthException, PermissionBackendException {
- for (DynamicMap.Entry<Cache<?, ?>> e : cacheMap) {
+ for (Extension<Cache<?, ?>> e : cacheMap) {
CacheResource cacheResource =
new CacheResource(e.getPluginName(), e.getExportName(), e.getProvider());
if (FlushCache.WEB_SESSIONS.equals(cacheResource.getName())) {
diff --git a/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java b/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java
index 60b5dee4ea..e1798962fb 100644
--- a/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java
+++ b/java/com/google/gerrit/server/restapi/project/ConfigInfoImpl.java
@@ -22,7 +22,7 @@ import com.google.gerrit.extensions.api.projects.ConfigInfo;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.common.ActionInfo;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicMap.Entry;
+import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
@@ -122,7 +122,7 @@ public class ConfigInfoImpl extends ConfigInfo {
PluginConfigFactory cfgFactory,
AllProjectsName allProjects) {
TreeMap<String, Map<String, ConfigParameterInfo>> pluginConfig = new TreeMap<>();
- for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
+ for (Extension<ProjectConfigEntry> e : pluginConfigEntries) {
ProjectConfigEntry configEntry = e.getProvider().get();
PluginConfig cfg = cfgFactory.getFromProjectConfig(project, e.getPluginName());
String configuredValue = cfg.getString(e.getExportName());
@@ -165,7 +165,7 @@ public class ConfigInfoImpl extends ConfigInfo {
}
private String getInheritedValue(
- ProjectState project, PluginConfigFactory cfgFactory, Entry<ProjectConfigEntry> e) {
+ ProjectState project, PluginConfigFactory cfgFactory, Extension<ProjectConfigEntry> e) {
ProjectConfigEntry configEntry = e.getProvider().get();
ProjectState parent = Iterables.getFirst(project.parents(), null);
String inheritedValue = configEntry.getDefaultValue();
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index 271848b9de..030402e18d 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -203,6 +203,10 @@ public class CreateProject
MoreObjects.firstNonNull(input.requireChangeId, InheritableBoolean.INHERIT);
args.rejectEmptyCommit =
MoreObjects.firstNonNull(input.rejectEmptyCommit, InheritableBoolean.INHERIT);
+ args.enableSignedPush =
+ MoreObjects.firstNonNull(input.enableSignedPush, InheritableBoolean.INHERIT);
+ args.requireSignedPush =
+ MoreObjects.firstNonNull(input.requireSignedPush, InheritableBoolean.INHERIT);
try {
args.maxObjectSizeLimit = ProjectConfig.validMaxObjectSizeLimit(input.maxObjectSizeLimit);
} catch (ConfigInvalidException e) {
@@ -297,6 +301,8 @@ public class CreateProject
newProject.setBooleanConfig(BooleanProjectConfig.REQUIRE_CHANGE_ID, args.changeIdRequired);
newProject.setBooleanConfig(BooleanProjectConfig.REJECT_EMPTY_COMMIT, args.rejectEmptyCommit);
newProject.setMaxObjectSizeLimit(args.maxObjectSizeLimit);
+ newProject.setBooleanConfig(BooleanProjectConfig.ENABLE_SIGNED_PUSH, args.enableSignedPush);
+ newProject.setBooleanConfig(BooleanProjectConfig.REQUIRE_SIGNED_PUSH, args.requireSignedPush);
if (args.newParent != null) {
newProject.setParentName(args.newParent);
}
diff --git a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
index 3b7f3e3d74..e0b2d93f7e 100644
--- a/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
+++ b/java/com/google/gerrit/server/restapi/project/GarbageCollect.java
@@ -16,6 +16,7 @@ package com.google.gerrit.server.restapi.project;
import static java.nio.charset.StandardCharsets.UTF_8;
+import com.google.common.base.Preconditions;
import com.google.gerrit.common.data.GarbageCollectionResult;
import com.google.gerrit.common.data.GlobalCapability;
import com.google.gerrit.extensions.annotations.RequiresCapability;
@@ -24,7 +25,7 @@ import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.git.GarbageCollection;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
@@ -33,13 +34,13 @@ import com.google.gerrit.server.ioutil.HexFormat;
import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.restapi.project.GarbageCollect.Input;
import com.google.inject.Inject;
-import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Collections;
+import java.util.Optional;
@RequiresCapability(GlobalCapability.RUN_GC)
@Singleton
@@ -54,16 +55,16 @@ public class GarbageCollect
private final boolean canGC;
private final GarbageCollection.Factory garbageCollectionFactory;
private final WorkQueue workQueue;
- private final Provider<String> canonicalUrl;
+ private final UrlFormatter urlFormatter;
@Inject
GarbageCollect(
GitRepositoryManager repoManager,
GarbageCollection.Factory garbageCollectionFactory,
WorkQueue workQueue,
- @CanonicalWebUrl Provider<String> canonicalUrl) {
+ UrlFormatter urlFormatter) {
this.workQueue = workQueue;
- this.canonicalUrl = canonicalUrl;
+ this.urlFormatter = urlFormatter;
this.canGC = repoManager instanceof LocalDiskRepositoryManager;
this.garbageCollectionFactory = garbageCollectionFactory;
}
@@ -97,10 +98,11 @@ public class GarbageCollect
@SuppressWarnings("unchecked")
WorkQueue.Task<Void> task = (WorkQueue.Task<Void>) workQueue.getDefaultQueue().submit(job);
- String location =
- canonicalUrl.get() + "a/config/server/tasks/" + HexFormat.fromInt(task.getTaskId());
-
- return Response.accepted(location);
+ Optional<String> url =
+ urlFormatter.getRestUrl("a/config/server/tasks/" + HexFormat.fromInt(task.getTaskId()));
+ // We're in a HTTP handler, so must be present.
+ Preconditions.checkState(url.isPresent());
+ return Response.accepted(url.get());
}
@SuppressWarnings("resource")
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
index 8e1ba6bf34..6abf102d65 100644
--- a/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
+++ b/java/com/google/gerrit/server/restapi/project/ProjectsCollection.java
@@ -15,6 +15,7 @@
package com.google.gerrit.server.restapi.project;
import com.google.common.collect.ListMultimap;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
@@ -46,6 +47,8 @@ import org.eclipse.jgit.lib.Constants;
@Singleton
public class ProjectsCollection
implements RestCollection<TopLevelResource, ProjectResource>, NeedsParams {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
private final DynamicMap<RestView<ProjectResource>> views;
private final Provider<ListProjects> list;
private final Provider<QueryProjects> queryProjects;
@@ -143,6 +146,8 @@ public class ProjectsCollection
return null;
}
+ logger.atFine().log("Project %s has state %s", nameKey, state.getProject().getState());
+
if (checkAccess) {
// Hidden projects(permitsRead = false) should only be accessible by the project owners.
// WRITE_CONFIG is checked here because it's only allowed to project owners (ACCESS may also
diff --git a/java/com/google/gerrit/server/submit/MergeSorter.java b/java/com/google/gerrit/server/submit/MergeSorter.java
index 8b9b1cc89a..14a2913865 100644
--- a/java/com/google/gerrit/server/submit/MergeSorter.java
+++ b/java/com/google/gerrit/server/submit/MergeSorter.java
@@ -14,6 +14,7 @@
package com.google.gerrit.server.submit;
+import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
import java.io.IOException;
@@ -26,6 +27,8 @@ import org.eclipse.jgit.revwalk.RevCommitList;
import org.eclipse.jgit.revwalk.RevFlag;
public class MergeSorter {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
private final CodeReviewRevWalk rw;
private final RevFlag canMergeFlag;
private final Set<RevCommit> accepted;
@@ -62,6 +65,8 @@ public class MergeSorter {
// We cannot merge n as it would bring something we
// aren't permitted to merge at this time. Drop n.
//
+ logger.atFine().log(
+ "commit %s depends on commit %s which cannot be merged", n.name(), c.name());
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
break;
}
diff --git a/java/com/google/gerrit/server/submit/RebaseSorter.java b/java/com/google/gerrit/server/submit/RebaseSorter.java
index 7ec8b0e139..a2d07fa274 100644
--- a/java/com/google/gerrit/server/submit/RebaseSorter.java
+++ b/java/com/google/gerrit/server/submit/RebaseSorter.java
@@ -81,6 +81,8 @@ public class RebaseSorter {
// We cannot merge n as it would bring something we
// aren't permitted to merge at this time. Drop n.
//
+ logger.atFine().log(
+ "commit %s depends on commit %s which cannot be merged", n.name(), c.name());
n.setStatusCode(CommitMergeStatus.MISSING_DEPENDENCY);
}
// Stop RevWalk because c is either a merged commit or a missing
diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
index 395a797895..72878eea67 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeIT.java
@@ -2585,7 +2585,7 @@ public class ChangeIT extends AbstractDaemonTest {
List<String> expectedFooters =
Arrays.asList(
"Change-Id: " + r2.getChangeId(),
- "Reviewed-on: " + canonicalWebUrl.get() + r2.getChange().getId(),
+ "Reviewed-on: " + canonicalWebUrl.get() + "c/" + r2.getChange().getId(),
"Reviewed-by: Administrator <admin@example.com>",
"Custom2: Administrator <admin@example.com>",
"Tested-by: Administrator <admin@example.com>");
@@ -2627,7 +2627,7 @@ public class ChangeIT extends AbstractDaemonTest {
List<String> expectedFooters =
Arrays.asList(
"Change-Id: " + change.getChangeId(),
- "Reviewed-on: " + canonicalWebUrl.get() + change.getChange().getId(),
+ "Reviewed-on: " + canonicalWebUrl.get() + "c/" + change.getChange().getId(),
"Custom: refs/heads/master");
assertThat(footers).containsExactlyElementsIn(expectedFooters);
}
diff --git a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
index d581c1e7a1..8891deef08 100644
--- a/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
+++ b/javatests/com/google/gerrit/acceptance/git/AbstractPushForReview.java
@@ -231,6 +231,15 @@ public abstract class AbstractPushForReview extends AbstractDaemonTest {
}
@Test
+ @GerritConfig(name = "receive.enableSignedPush", value = "true")
+ @TestProjectInput(
+ enableSignedPush = InheritableBoolean.TRUE,
+ requireSignedPush = InheritableBoolean.TRUE)
+ public void nonSignedPushRejectedWhenSignPushRequired() throws Exception {
+ pushTo("refs/for/master").assertErrorStatus("push cert error");
+ }
+
+ @Test
public void pushInitialCommitForRefsMetaConfigBranch() throws Exception {
// delete refs/meta/config
try (Repository repo = repoManager.openRepository(project);
diff --git a/javatests/com/google/gerrit/extensions/registration/DynamicSetTest.java b/javatests/com/google/gerrit/extensions/registration/DynamicSetTest.java
index c86160f9bb..0542c35d1c 100644
--- a/javatests/com/google/gerrit/extensions/registration/DynamicSetTest.java
+++ b/javatests/com/google/gerrit/extensions/registration/DynamicSetTest.java
@@ -123,8 +123,8 @@ public class DynamicSetTest {
ds.add("bar", 2);
ds.add("bar", 3);
- Iterator<DynamicSet.Entry<Integer>> entryIterator = ds.entries().iterator();
- DynamicSet.Entry<Integer> next = entryIterator.next();
+ Iterator<Extension<Integer>> entryIterator = ds.entries().iterator();
+ Extension<Integer> next = entryIterator.next();
assertThat(next.getPluginName()).isEqualTo("foo");
assertThat(next.getProvider().get()).isEqualTo(1);
diff --git a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
index f8ab417435..685f42de42 100644
--- a/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
+++ b/javatests/com/google/gerrit/gpg/GerritPublicKeyCheckerTest.java
@@ -232,7 +232,7 @@ public class GerritPublicKeyCheckerTest {
assertProblems(
checker.check(key.getPublicKey()),
Status.BAD,
- "No identities found for user; check http://test/#/settings/web-identities");
+ "No identities found for user; check http://test/settings#Identities");
checker = checkerFactory.create().setStore(store).disableTrust();
assertProblems(
diff --git a/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java b/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
index b93e9c13eb..0c4a47f0dd 100644
--- a/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
+++ b/javatests/com/google/gerrit/server/notedb/AbstractChangeNotesTest.java
@@ -42,9 +42,11 @@ import com.google.gerrit.server.config.AllUsersNameProvider;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.AnonymousCowardNameProvider;
import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.config.DefaultBrowseUrls;
import com.google.gerrit.server.config.DisableReverseDnsLookup;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GerritServerId;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitModule;
import com.google.gerrit.server.git.GitRepositoryManager;
@@ -162,6 +164,7 @@ public abstract class AbstractChangeNotesTest extends GerritBaseTests {
migration.setFrom(NotesMigrationState.FINAL);
bind(MutableNotesMigration.class).toInstance(migration);
bind(NotesMigration.class).to(MutableNotesMigration.class);
+ bind(UrlFormatter.class).to(DefaultBrowseUrls.class);
// Tests don't support ReviewDb at all, but bindings are required via NoteDbModule.
bind(new TypeLiteral<SchemaFactory<ReviewDb>>() {})
diff --git a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index f3275d15f9..b9973e906c 100644
--- a/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -841,6 +841,43 @@ public abstract class AbstractQueryChangesTest extends GerritServerTests {
}
@Test
+ public void byRepo() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("repo:foo");
+ assertQuery("repo:repo");
+ assertQuery("repo:repo1", change1);
+ assertQuery("repo:repo2", change2);
+ }
+
+ @Test
+ public void byParentRepo() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2", "repo1");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("parentrepo:repo1", change2, change1);
+ assertQuery("parentrepo:repo2", change2);
+ }
+
+ @Test
+ public void byRepoPrefix() throws Exception {
+ TestRepository<Repo> repo1 = createProject("repo1");
+ TestRepository<Repo> repo2 = createProject("repo2");
+ Change change1 = insert(repo1, newChange(repo1));
+ Change change2 = insert(repo2, newChange(repo2));
+
+ assertQuery("repos:foo");
+ assertQuery("repos:repo1", change1);
+ assertQuery("repos:repo2", change2);
+ assertQuery("repos:repo", change2, change1);
+ }
+
+ @Test
public void byBranchAndRef() throws Exception {
TestRepository<Repo> repo = createProject("repo");
Change change1 = insert(repo, newChangeForBranch(repo, "master"));
diff --git a/lib/polymer_externs/BUILD b/lib/polymer_externs/BUILD
index ae8f9c0ffe..2f1bdbded2 100644
--- a/lib/polymer_externs/BUILD
+++ b/lib/polymer_externs/BUILD
@@ -18,16 +18,9 @@ package(
load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library")
-genrule(
- name = "polymer_closure_renamed",
- srcs = ["@polymer_closure//file"],
- outs = ["polymer_closure_renamed.js"],
- cmd = "cp $< $@",
-)
-
closure_js_library(
name = "polymer_closure",
- srcs = [":polymer_closure_renamed"],
+ srcs = ["@polymer_closure//file"],
data = ["//lib:LICENSE-Apache2.0"],
no_closure_library = True,
)
diff --git a/plugins/hooks b/plugins/hooks
-Subproject 7185e5ce46646e952071befd9cf8f4267560b51
+Subproject de469e8e2598779773652abb43a0356650e257b
diff --git a/plugins/reviewnotes b/plugins/reviewnotes
-Subproject 54525ffaed5e8925d97657a622532a00a000634
+Subproject 543ae1f0a24dda61d4f36b173b9bddfd52ead3b