Merge changes I235f2510,I9d97b664,I47a02929
* changes:
Update org.apache.mina:mina-core to 2.0.27
Update JGit to f22643b39 and apache sshd to 2.15.0
Update bouncycastle to 1.80
diff --git a/contrib/migrate-to-h2-v2.sh b/contrib/migrate-to-h2-v2.sh
new file mode 100755
index 0000000..221b68c
--- /dev/null
+++ b/contrib/migrate-to-h2-v2.sh
@@ -0,0 +1,76 @@
+#!/bin/bash -e
+
+# Copyright (C) 2025 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.
+
+OLD_H2_VERSION=1.3.176
+NEW_H2_VERSION=2.3.232
+
+usage() {
+ me=`basename "$0"`
+ echo >&2 "Usage: $me [--help] [--site SITE] [--output DST]"
+ exit 1
+}
+
+while test $# -gt 0 ; do
+ case "$1" in
+ --help)
+ usage
+ ;;
+
+ --site)
+ shift
+ SITE=$1
+ shift
+ ;;
+
+ --output)
+ shift
+ DST=$1
+ shift
+ ;;
+ *)
+ break
+ esac
+done
+
+test -z $SITE && usage
+SRC=$SITE/cache
+
+test -z $DST && DST=$SRC
+
+mkdir -p $DST
+rm -rf $DST/*-v2.mv.db
+
+test -f h2-$NEW_H2_VERSION.jar || \
+ wget https://repo1.maven.org/maven2/com/h2database/h2/$NEW_H2_VERSION/h2-$NEW_H2_VERSION.jar
+test -f h2-$OLD_H2_VERSION.jar || \
+ wget https://repo1.maven.org/maven2/com/h2database/h2/$OLD_H2_VERSION/h2-$OLD_H2_VERSION.jar
+
+for filepath in $SRC/*.h2.db; do
+ DB_NAME=$(basename "$filepath" .h2.db)
+
+ echo "Exporting database $DB_NAME ..."
+ cp $filepath $DST/${DB_NAME}_tmp.h2.db
+ java -cp h2-$OLD_H2_VERSION.jar org.h2.tools.Shell -url jdbc:h2:$DST/${DB_NAME}_tmp -sql 'ALTER TABLE public.data DROP COLUMN IF EXISTS space;'
+ java -cp h2-$OLD_H2_VERSION.jar org.h2.tools.Script -url jdbc:h2:$DST/${DB_NAME}_tmp -script backup-$DB_NAME.zip -options compression zip
+
+ echo "Importing data of $DB_NAME..."
+ java -cp h2-$NEW_H2_VERSION.jar org.h2.tools.RunScript -url jdbc:h2:$DST/$DB_NAME-v2 -script ./backup-$DB_NAME.zip -options compression zip FROM_1X
+ java -cp h2-$NEW_H2_VERSION.jar org.h2.tools.Shell -url jdbc:h2:$DST/$DB_NAME-v2 -sql 'ALTER TABLE public.data ADD COLUMN IF NOT EXISTS space BIGINT AS OCTET_LENGTH(k) + OCTET_LENGTH(v);'
+
+ rm -f backup-$DB_NAME.zip
+ rm -rf $DST/${DB_NAME}_tmp.h2.db
+ echo "$DB_NAME migrated succesfully"
+done
diff --git a/java/com/google/gerrit/extensions/api/projects/TagInfo.java b/java/com/google/gerrit/extensions/api/projects/TagInfo.java
index 61ea518..9bb15a9 100644
--- a/java/com/google/gerrit/extensions/api/projects/TagInfo.java
+++ b/java/com/google/gerrit/extensions/api/projects/TagInfo.java
@@ -26,7 +26,7 @@
public String message;
public GitPerson tagger;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp created;
diff --git a/java/com/google/gerrit/extensions/client/Comment.java b/java/com/google/gerrit/extensions/client/Comment.java
index 187c84f..4bfa566 100644
--- a/java/com/google/gerrit/extensions/client/Comment.java
+++ b/java/com/google/gerrit/extensions/client/Comment.java
@@ -40,7 +40,7 @@
public Range range;
public String inReplyTo;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp updated;
@@ -54,14 +54,14 @@
public List<FixSuggestionInfo> fixSuggestions;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public Instant getUpdated() {
return updated.toInstant();
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setUpdated(Instant when) {
diff --git a/java/com/google/gerrit/extensions/common/AccountDetailInfo.java b/java/com/google/gerrit/extensions/common/AccountDetailInfo.java
index a76a7f9..a891d8c 100644
--- a/java/com/google/gerrit/extensions/common/AccountDetailInfo.java
+++ b/java/com/google/gerrit/extensions/common/AccountDetailInfo.java
@@ -28,7 +28,7 @@
*/
public class AccountDetailInfo extends AccountInfo {
/** The timestamp of when the account was registered. */
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp registeredOn;
@@ -36,7 +36,7 @@
super(id);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setRegisteredOn(Instant registeredOn) {
diff --git a/java/com/google/gerrit/extensions/common/ApprovalInfo.java b/java/com/google/gerrit/extensions/common/ApprovalInfo.java
index 4519add..9147b51 100644
--- a/java/com/google/gerrit/extensions/common/ApprovalInfo.java
+++ b/java/com/google/gerrit/extensions/common/ApprovalInfo.java
@@ -44,7 +44,7 @@
public Integer value;
/** The time and date describing when the approval was made. */
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp date;
@@ -91,7 +91,7 @@
}
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setDate(Instant date) {
diff --git a/java/com/google/gerrit/extensions/common/AttentionSetInfo.java b/java/com/google/gerrit/extensions/common/AttentionSetInfo.java
index 81dbc88..b220371 100644
--- a/java/com/google/gerrit/extensions/common/AttentionSetInfo.java
+++ b/java/com/google/gerrit/extensions/common/AttentionSetInfo.java
@@ -31,7 +31,7 @@
public AccountInfo account;
/** The timestamp of the last update. */
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp lastUpdate;
@@ -56,7 +56,7 @@
this.reasonAccount = reasonAccount;
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public AttentionSetInfo(
diff --git a/java/com/google/gerrit/extensions/common/ChangeInfo.java b/java/com/google/gerrit/extensions/common/ChangeInfo.java
index 63e9c61..28d99de 100644
--- a/java/com/google/gerrit/extensions/common/ChangeInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeInfo.java
@@ -59,7 +59,7 @@
public String subject;
public ChangeStatus status;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp created;
public Timestamp updated;
@@ -140,42 +140,42 @@
this.revisions = ImmutableMap.copyOf(revisions);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public Instant getCreated() {
return created.toInstant();
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setCreated(Instant when) {
created = Timestamp.from(when);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public Instant getUpdated() {
return updated.toInstant();
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setUpdated(Instant when) {
updated = Timestamp.from(when);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public Instant getSubmitted() {
return submitted.toInstant();
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setSubmitted(Instant when, AccountInfo who) {
diff --git a/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java b/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
index 51fe57c..c128f36 100644
--- a/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
+++ b/java/com/google/gerrit/extensions/common/ChangeMessageInfo.java
@@ -27,7 +27,7 @@
public AccountInfo author;
public AccountInfo realAuthor;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp date;
@@ -41,7 +41,7 @@
this.message = message;
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setDate(Instant when) {
diff --git a/java/com/google/gerrit/extensions/common/GitPerson.java b/java/com/google/gerrit/extensions/common/GitPerson.java
index df3e488..98481c5 100644
--- a/java/com/google/gerrit/extensions/common/GitPerson.java
+++ b/java/com/google/gerrit/extensions/common/GitPerson.java
@@ -22,13 +22,13 @@
public String name;
public String email;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp date;
public int tz;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setDate(Instant when) {
diff --git a/java/com/google/gerrit/extensions/common/GroupAuditEventInfo.java b/java/com/google/gerrit/extensions/common/GroupAuditEventInfo.java
index 9a13713..de0f4e0 100644
--- a/java/com/google/gerrit/extensions/common/GroupAuditEventInfo.java
+++ b/java/com/google/gerrit/extensions/common/GroupAuditEventInfo.java
@@ -30,11 +30,11 @@
public Type type;
public AccountInfo user;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp date;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public static UserMemberAuditEventInfo createAddUserEvent(
@@ -47,7 +47,7 @@
return new UserMemberAuditEventInfo(Type.ADD_USER, user, date, member);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public static UserMemberAuditEventInfo createRemoveUserEvent(
@@ -61,7 +61,7 @@
return new UserMemberAuditEventInfo(Type.REMOVE_USER, user, date, member);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public static GroupMemberAuditEventInfo createAddGroupEvent(
@@ -74,7 +74,7 @@
return new GroupMemberAuditEventInfo(Type.ADD_GROUP, user, date, member);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public static GroupMemberAuditEventInfo createRemoveGroupEvent(
@@ -94,7 +94,7 @@
this.date = date.orElse(null);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
protected GroupAuditEventInfo(Type type, AccountInfo user, @Nullable Instant date) {
diff --git a/java/com/google/gerrit/extensions/common/GroupInfo.java b/java/com/google/gerrit/extensions/common/GroupInfo.java
index edbaa01..cde2aa4 100644
--- a/java/com/google/gerrit/extensions/common/GroupInfo.java
+++ b/java/com/google/gerrit/extensions/common/GroupInfo.java
@@ -28,7 +28,7 @@
public String owner;
public String ownerId;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp createdOn;
@@ -38,14 +38,14 @@
public List<AccountInfo> members;
public List<GroupInfo> includes;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public Instant getCreatedOn() {
return createdOn.toInstant();
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setCreatedOn(Instant when) {
diff --git a/java/com/google/gerrit/extensions/common/ReviewerUpdateInfo.java b/java/com/google/gerrit/extensions/common/ReviewerUpdateInfo.java
index 36682f6..8f2d38c 100644
--- a/java/com/google/gerrit/extensions/common/ReviewerUpdateInfo.java
+++ b/java/com/google/gerrit/extensions/common/ReviewerUpdateInfo.java
@@ -20,7 +20,7 @@
import java.util.Objects;
public class ReviewerUpdateInfo {
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp updated;
@@ -30,7 +30,7 @@
public ReviewerUpdateInfo() {}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public ReviewerUpdateInfo(
diff --git a/java/com/google/gerrit/extensions/common/RevisionInfo.java b/java/com/google/gerrit/extensions/common/RevisionInfo.java
index dc134fb..8a88dd2 100644
--- a/java/com/google/gerrit/extensions/common/RevisionInfo.java
+++ b/java/com/google/gerrit/extensions/common/RevisionInfo.java
@@ -28,7 +28,7 @@
public ChangeKind kind;
public int _number;
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
public Timestamp created;
@@ -69,7 +69,7 @@
this.uploader = uploader;
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void setCreated(Instant date) {
diff --git a/java/com/google/gerrit/extensions/common/testing/GitPersonSubject.java b/java/com/google/gerrit/extensions/common/testing/GitPersonSubject.java
index f75ec66..de7e5f1 100644
--- a/java/com/google/gerrit/extensions/common/testing/GitPersonSubject.java
+++ b/java/com/google/gerrit/extensions/common/testing/GitPersonSubject.java
@@ -70,7 +70,7 @@
tz().isEqualTo(other.tz);
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
public void matches(PersonIdent ident) {
diff --git a/java/com/google/gerrit/httpd/EnableTracingFilter.java b/java/com/google/gerrit/httpd/EnableTracingFilter.java
new file mode 100644
index 0000000..c91be4b
--- /dev/null
+++ b/java/com/google/gerrit/httpd/EnableTracingFilter.java
@@ -0,0 +1,100 @@
+// Copyright (C) 2024 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.httpd;
+
+import static com.google.gerrit.httpd.GerritHeaders.X_GERRIT_TRACE;
+
+import com.google.common.base.Strings;
+import com.google.gerrit.httpd.restapi.ParameterParser;
+import com.google.gerrit.server.logging.RequestId;
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * This filter associates a trace ID to each http request. If requested, forced tracing is also
+ * enabled.
+ *
+ * <p>There are 2 ways to force tracing for http requests: 1. by using the 'trace' or
+ * 'trace=<trace-id>' request parameter 2. by setting the 'X-Gerrit-Trace:' or
+ * 'X-Gerrit-Trace:<trace-id>' header
+ */
+@Singleton
+public class EnableTracingFilter implements Filter {
+
+ public static final String REQUEST_TRACE_CONTEXT = "REQUEST_TRACE_CONTEXT";
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {}
+
+ private int count;
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+ throws IOException, ServletException {
+ System.out.printf("%d EnableTracingFilter.doFilter\n", ++count);
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpServletResponse res = (HttpServletResponse) response;
+ try (TraceContext traceContext = enableTracing(req, res)) {
+ request.setAttribute(REQUEST_TRACE_CONTEXT, traceContext);
+ chain.doFilter(request, response);
+ }
+ }
+
+ private TraceContext enableTracing(HttpServletRequest req, HttpServletResponse res) {
+ String traceValueFromHeader = req.getHeader(X_GERRIT_TRACE);
+ String traceValueFromRequestParam = req.getParameter(ParameterParser.TRACE_PARAMETER);
+ boolean forceLogging = traceValueFromHeader != null || traceValueFromRequestParam != null;
+
+ // Check whether no trace ID, one trace ID or 2 different trace IDs have been specified.
+ String traceId1;
+ String traceId2;
+ if (!Strings.isNullOrEmpty(traceValueFromHeader)) {
+ traceId1 = traceValueFromHeader;
+ if (!Strings.isNullOrEmpty(traceValueFromRequestParam)
+ && !traceValueFromHeader.equals(traceValueFromRequestParam)) {
+ traceId2 = traceValueFromRequestParam;
+ } else {
+ traceId2 = null;
+ }
+ } else {
+ traceId1 = Strings.emptyToNull(traceValueFromRequestParam);
+ traceId2 = null;
+ }
+
+ // Use the first trace ID to start tracing. If this trace ID is null, a trace ID will be
+ // generated.
+ TraceContext traceContext =
+ TraceContext.newTrace(
+ forceLogging, traceId1, (tagName, traceId) -> res.setHeader(X_GERRIT_TRACE, traceId));
+ // If a second trace ID was specified, add a tag for it as well.
+ if (traceId2 != null) {
+ traceContext.addTag(RequestId.Type.TRACE_ID, traceId2);
+ res.addHeader(X_GERRIT_TRACE, traceId2);
+ }
+ return traceContext;
+ }
+
+ @Override
+ public void destroy() {}
+}
diff --git a/java/com/google/gerrit/httpd/GerritHeaders.java b/java/com/google/gerrit/httpd/GerritHeaders.java
new file mode 100644
index 0000000..e5be906
--- /dev/null
+++ b/java/com/google/gerrit/httpd/GerritHeaders.java
@@ -0,0 +1,19 @@
+// Copyright (C) 2024 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.httpd;
+
+public class GerritHeaders {
+ public static final String X_GERRIT_TRACE = "X-Gerrit-Trace";
+}
diff --git a/java/com/google/gerrit/httpd/HttpRequestTraceModule.java b/java/com/google/gerrit/httpd/HttpRequestTraceModule.java
new file mode 100644
index 0000000..ea36fbc
--- /dev/null
+++ b/java/com/google/gerrit/httpd/HttpRequestTraceModule.java
@@ -0,0 +1,39 @@
+// Copyright (C) 2024 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.httpd;
+
+import static com.google.gerrit.httpd.EnableTracingFilter.REQUEST_TRACE_CONTEXT;
+
+import com.google.gerrit.server.logging.TraceContext;
+import com.google.inject.Provides;
+import com.google.inject.name.Named;
+import com.google.inject.servlet.RequestScoped;
+import com.google.inject.servlet.ServletModule;
+import javax.servlet.http.HttpServletRequest;
+
+public class HttpRequestTraceModule extends ServletModule {
+
+ @Provides
+ @RequestScoped
+ @Named(REQUEST_TRACE_CONTEXT)
+ public TraceContext provideTraceContext(HttpServletRequest req) {
+ return (TraceContext) req.getAttribute(REQUEST_TRACE_CONTEXT);
+ }
+
+ @Override
+ protected void configureServlets() {
+ filter("/*").through(EnableTracingFilter.class);
+ }
+}
diff --git a/java/com/google/gerrit/httpd/ProxyPropertiesProvider.java b/java/com/google/gerrit/httpd/ProxyPropertiesProvider.java
index b0a8013..9b8c827 100644
--- a/java/com/google/gerrit/httpd/ProxyPropertiesProvider.java
+++ b/java/com/google/gerrit/httpd/ProxyPropertiesProvider.java
@@ -20,6 +20,7 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import org.eclipse.jgit.lib.Config;
@@ -34,7 +35,7 @@
ProxyPropertiesProvider(@GerritServerConfig Config config) throws MalformedURLException {
String proxyUrlStr = config.getString("http", null, "proxy");
if (!Strings.isNullOrEmpty(proxyUrlStr)) {
- proxyUrl = new URL(proxyUrlStr);
+ proxyUrl = URI.create(proxyUrlStr).toURL();
proxyUser = config.getString("http", null, "proxyUsername");
proxyPassword = config.getString("http", null, "proxyPassword");
String userInfo = proxyUrl.getUserInfo();
diff --git a/java/com/google/gerrit/httpd/WebModule.java b/java/com/google/gerrit/httpd/WebModule.java
index 5a6a84c..d0c8250 100644
--- a/java/com/google/gerrit/httpd/WebModule.java
+++ b/java/com/google/gerrit/httpd/WebModule.java
@@ -49,6 +49,8 @@
@Override
protected void configure() {
+ install(new HttpRequestTraceModule());
+
bind(RequestScopePropagator.class).to(GuiceRequestScopePropagator.class);
bind(HttpRequestContext.class);
diff --git a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
index 8fe7d79..66544c2 100644
--- a/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
+++ b/java/com/google/gerrit/httpd/restapi/RestApiServlet.java
@@ -19,6 +19,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
+import static com.google.gerrit.httpd.EnableTracingFilter.REQUEST_TRACE_CONTEXT;
import static java.math.RoundingMode.CEILING;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -142,6 +143,7 @@
import com.google.inject.Injector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
+import com.google.inject.name.Named;
import com.google.inject.util.Providers;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -245,6 +247,7 @@
final DeadlineChecker.Factory deadlineCheckerFactory;
final CancellationMetrics cancellationMetrics;
final AclInfoController aclInfoController;
+ final Provider<TraceContext> requestTraceContext;
@Inject
Globals(
@@ -265,7 +268,8 @@
DynamicMap<DynamicOptions.DynamicBean> dynamicBeans,
DeadlineChecker.Factory deadlineCheckerFactory,
CancellationMetrics cancellationMetrics,
- AclInfoController aclInfoController) {
+ AclInfoController aclInfoController,
+ @Named(REQUEST_TRACE_CONTEXT) Provider<TraceContext> requestTraceContext) {
this.currentUser = currentUser;
this.webSession = webSession;
this.paramParser = paramParser;
@@ -285,6 +289,7 @@
this.deadlineCheckerFactory = deadlineCheckerFactory;
this.cancellationMetrics = cancellationMetrics;
this.aclInfoController = aclInfoController;
+ this.requestTraceContext = requestTraceContext;
}
}
@@ -331,456 +336,444 @@
String sessionId = globals.webSession.get().getSessionId();
CurrentUser currentUser = globals.currentUser.get();
- try (TraceContext traceContext = enableTracing(req, res)) {
- String requestUri = requestUri(req);
+ String requestUri = requestUri(req);
- try (PerThreadCache ignored = PerThreadCache.create()) {
- List<IdString> path = splitPath(req);
- RequestInfo requestInfo = createRequestInfo(traceContext, req, requestUri, path);
- globals.requestListeners.runEach(l -> l.onRequest(requestInfo));
+ try (PerThreadCache ignored = PerThreadCache.create()) {
+ List<IdString> path = splitPath(req);
+ TraceContext traceContext = globals.requestTraceContext.get();
+ RequestInfo requestInfo = createRequestInfo(traceContext, req, requestUri, path);
+ globals.requestListeners.runEach(l -> l.onRequest(requestInfo));
- globals.aclInfoController.enableAclLoggingIfUserCanViewAccess(traceContext);
+ globals.aclInfoController.enableAclLoggingIfUserCanViewAccess(traceContext);
- // It's important that the PerformanceLogContext is closed before the response is sent to
- // the client. Only this way it is ensured that the invocation of the PerformanceLogger
- // plugins happens before the client sees the response. This is needed for being able to
- // test performance logging from an acceptance test (see
- // TraceIT#performanceLoggingForRestCall()).
- try (RequestStateContext requestStateContext =
- RequestStateContext.open()
- .addRequestStateProvider(
- globals.deadlineCheckerFactory.create(
- requestInfo, req.getHeader(X_GERRIT_DEADLINE)));
- PerformanceLogContext performanceLogContext =
- new PerformanceLogContext(globals.config, globals.performanceLoggers)) {
- traceRequestData(req);
+ // It's important that the PerformanceLogContext is closed before the response is sent to
+ // the client. Only this way it is ensured that the invocation of the PerformanceLogger
+ // plugins happens before the client sees the response. This is needed for being able to
+ // test performance logging from an acceptance test (see
+ // TraceIT#performanceLoggingForRestCall()).
+ try (RequestStateContext requestStateContext =
+ RequestStateContext.open()
+ .addRequestStateProvider(
+ globals.deadlineCheckerFactory.create(
+ requestInfo, req.getHeader(X_GERRIT_DEADLINE)));
+ PerformanceLogContext performanceLogContext =
+ new PerformanceLogContext(globals.config, globals.performanceLoggers)) {
+ traceRequestData(req);
- if (corsResponder.filterCorsPreflight(req, res)) {
- return;
+ if (corsResponder.filterCorsPreflight(req, res)) {
+ return;
+ }
+
+ qp = ParameterParser.getQueryParams(req);
+ corsResponder.checkCors(req, res, qp.hasXdOverride());
+ if (qp.hasXdOverride()) {
+ req = applyXdOverrides(req, qp);
+ }
+ checkUserSession(req);
+
+ RestCollection<RestResource, RestResource> rc = members.get();
+ globals
+ .permissionBackend
+ .currentUser()
+ .checkAny(GlobalPermission.fromAnnotation(rc.getClass()));
+
+ viewData = new ViewData(null, null);
+
+ if (path.isEmpty()) {
+ globals.quotaChecker.enforce(req);
+ if (rc instanceof NeedsParams) {
+ ((NeedsParams) rc).setParams(qp.params());
}
- qp = ParameterParser.getQueryParams(req);
- corsResponder.checkCors(req, res, qp.hasXdOverride());
- if (qp.hasXdOverride()) {
- req = applyXdOverrides(req, qp);
+ if (isRead(req)) {
+ viewData = new ViewData(null, rc.list());
+ } else if (isPost(req)) {
+ RestView<RestResource> restCollectionView =
+ rc.views().get(PluginName.GERRIT, "POST_ON_COLLECTION./");
+ if (restCollectionView != null) {
+ viewData = new ViewData(null, restCollectionView);
+ } else {
+ throw methodNotAllowed(req);
+ }
+ } else {
+ // DELETE on root collections is not supported
+ throw methodNotAllowed(req);
}
- checkUserSession(req);
+ } else {
+ IdString id = path.remove(0);
+ try {
+ rsrc = parseResourceWithRetry(req, traceContext, viewData.pluginName, rc, rsrc, id);
+ globals.quotaChecker.enforce(rsrc, req);
+ if (path.isEmpty()) {
+ checkPreconditions(req);
+ }
+ } catch (ResourceNotFoundException e) {
+ if (!path.isEmpty()) {
+ throw e;
+ }
+ globals.quotaChecker.enforce(req);
- RestCollection<RestResource, RestResource> rc = members.get();
- globals
- .permissionBackend
- .currentUser()
- .checkAny(GlobalPermission.fromAnnotation(rc.getClass()));
+ if (isPost(req) || isPut(req)) {
+ RestView<RestResource> createView = rc.views().get(PluginName.GERRIT, "CREATE./");
+ if (createView != null) {
+ viewData = new ViewData(null, createView);
+ path.add(id);
+ } else {
+ throw e;
+ }
+ } else if (isDelete(req)) {
+ RestView<RestResource> deleteView =
+ rc.views().get(PluginName.GERRIT, "DELETE_MISSING./");
+ if (deleteView != null) {
+ viewData = new ViewData(null, deleteView);
+ path.add(id);
+ } else {
+ throw e;
+ }
+ } else {
+ throw e;
+ }
+ }
+ if (viewData.view == null) {
+ viewData = view(rc, req.getMethod(), path);
+ }
+ }
+ checkRequiresCapability(viewData);
- viewData = new ViewData(null, null);
+ while (viewData.view instanceof RestCollection<?, ?>) {
+ @SuppressWarnings("unchecked")
+ RestCollection<RestResource, RestResource> c =
+ (RestCollection<RestResource, RestResource>) viewData.view;
if (path.isEmpty()) {
- globals.quotaChecker.enforce(req);
- if (rc instanceof NeedsParams) {
- ((NeedsParams) rc).setParams(qp.params());
- }
-
if (isRead(req)) {
- viewData = new ViewData(null, rc.list());
+ viewData = new ViewData(null, c.list());
} else if (isPost(req)) {
+ // TODO: Here and on other collection methods: There is a bug that binds child views
+ // with pluginName="gerrit" instead of the real plugin name. This has never worked
+ // correctly and should be fixed where the binding gets created (DynamicMapProvider)
+ // and here.
RestView<RestResource> restCollectionView =
- rc.views().get(PluginName.GERRIT, "POST_ON_COLLECTION./");
+ c.views().get(PluginName.GERRIT, "POST_ON_COLLECTION./");
+ if (restCollectionView != null) {
+ viewData = new ViewData(null, restCollectionView);
+ } else {
+ throw methodNotAllowed(req);
+ }
+ } else if (isDelete(req)) {
+ RestView<RestResource> restCollectionView =
+ c.views().get(PluginName.GERRIT, "DELETE_ON_COLLECTION./");
if (restCollectionView != null) {
viewData = new ViewData(null, restCollectionView);
} else {
throw methodNotAllowed(req);
}
} else {
- // DELETE on root collections is not supported
throw methodNotAllowed(req);
}
- } else {
- IdString id = path.remove(0);
- try {
- rsrc = parseResourceWithRetry(req, traceContext, viewData.pluginName, rc, rsrc, id);
- globals.quotaChecker.enforce(rsrc, req);
- if (path.isEmpty()) {
- checkPreconditions(req);
- }
- } catch (ResourceNotFoundException e) {
- if (!path.isEmpty()) {
- throw e;
- }
- globals.quotaChecker.enforce(req);
+ break;
+ }
+ IdString id = path.remove(0);
+ try {
+ rsrc = parseResourceWithRetry(req, traceContext, viewData.pluginName, c, rsrc, id);
+ checkPreconditions(req);
+ viewData = new ViewData(null, null);
+ } catch (ResourceNotFoundException e) {
+ if (!path.isEmpty()) {
+ throw e;
+ }
- if (isPost(req) || isPut(req)) {
- RestView<RestResource> createView = rc.views().get(PluginName.GERRIT, "CREATE./");
- if (createView != null) {
- viewData = new ViewData(null, createView);
- path.add(id);
- } else {
- throw e;
- }
- } else if (isDelete(req)) {
- RestView<RestResource> deleteView =
- rc.views().get(PluginName.GERRIT, "DELETE_MISSING./");
- if (deleteView != null) {
- viewData = new ViewData(null, deleteView);
- path.add(id);
- } else {
- throw e;
- }
+ if (isPost(req) || isPut(req)) {
+ RestView<RestResource> createView = c.views().get(PluginName.GERRIT, "CREATE./");
+ if (createView != null) {
+ viewData = new ViewData(viewData.pluginName, createView);
+ path.add(id);
} else {
throw e;
}
+ } else if (isDelete(req)) {
+ RestView<RestResource> deleteView =
+ c.views().get(PluginName.GERRIT, "DELETE_MISSING./");
+ if (deleteView != null) {
+ viewData = new ViewData(viewData.pluginName, deleteView);
+ path.add(id);
+ } else {
+ throw e;
+ }
+ } else {
+ throw e;
}
- if (viewData.view == null) {
- viewData = view(rc, req.getMethod(), path);
- }
+ }
+ if (viewData.view == null) {
+ viewData = view(c, req.getMethod(), path);
}
checkRequiresCapability(viewData);
+ }
- while (viewData.view instanceof RestCollection<?, ?>) {
- @SuppressWarnings("unchecked")
- RestCollection<RestResource, RestResource> c =
- (RestCollection<RestResource, RestResource>) viewData.view;
+ if (notModified(req, rsrc)) {
+ logger.atFinest().log("REST call succeeded: %d", SC_NOT_MODIFIED);
+ res.sendError(SC_NOT_MODIFIED);
+ return;
+ }
- if (path.isEmpty()) {
- if (isRead(req)) {
- viewData = new ViewData(null, c.list());
- } else if (isPost(req)) {
- // TODO: Here and on other collection methods: There is a bug that binds child views
- // with pluginName="gerrit" instead of the real plugin name. This has never worked
- // correctly and should be fixed where the binding gets created (DynamicMapProvider)
- // and here.
- RestView<RestResource> restCollectionView =
- c.views().get(PluginName.GERRIT, "POST_ON_COLLECTION./");
- if (restCollectionView != null) {
- viewData = new ViewData(null, restCollectionView);
- } else {
- throw methodNotAllowed(req);
- }
- } else if (isDelete(req)) {
- RestView<RestResource> restCollectionView =
- c.views().get(PluginName.GERRIT, "DELETE_ON_COLLECTION./");
- if (restCollectionView != null) {
- viewData = new ViewData(null, restCollectionView);
- } else {
- throw methodNotAllowed(req);
- }
- } else {
- throw methodNotAllowed(req);
- }
- break;
- }
- IdString id = path.remove(0);
- try {
- rsrc = parseResourceWithRetry(req, traceContext, viewData.pluginName, c, rsrc, id);
- checkPreconditions(req);
- viewData = new ViewData(null, null);
- } catch (ResourceNotFoundException e) {
- if (!path.isEmpty()) {
- throw e;
- }
-
- if (isPost(req) || isPut(req)) {
- RestView<RestResource> createView = c.views().get(PluginName.GERRIT, "CREATE./");
- if (createView != null) {
- viewData = new ViewData(viewData.pluginName, createView);
- path.add(id);
- } else {
- throw e;
- }
- } else if (isDelete(req)) {
- RestView<RestResource> deleteView =
- c.views().get(PluginName.GERRIT, "DELETE_MISSING./");
- if (deleteView != null) {
- viewData = new ViewData(viewData.pluginName, deleteView);
- path.add(id);
- } else {
- throw e;
- }
- } else {
- throw e;
- }
- }
- if (viewData.view == null) {
- viewData = view(c, req.getMethod(), path);
- }
- checkRequiresCapability(viewData);
- }
-
- if (notModified(req, rsrc)) {
- logger.atFinest().log("REST call succeeded: %d", SC_NOT_MODIFIED);
- res.sendError(SC_NOT_MODIFIED);
+ try (DynamicOptions pluginOptions =
+ new DynamicOptions(globals.injector, globals.dynamicBeans)) {
+ if (!globals
+ .paramParser
+ .get()
+ .parse(viewData.view, pluginOptions, qp.params(), req, res)) {
return;
}
- try (DynamicOptions pluginOptions =
- new DynamicOptions(globals.injector, globals.dynamicBeans)) {
- if (!globals
- .paramParser
- .get()
- .parse(viewData.view, pluginOptions, qp.params(), req, res)) {
- return;
- }
+ if (viewData.view instanceof RestReadView<?> && isRead(req)) {
+ response =
+ invokeRestReadViewWithRetry(
+ req, traceContext, viewData, (RestReadView<RestResource>) viewData.view, rsrc);
+ } else if (viewData.view instanceof RestModifyView<?, ?>) {
+ RestModifyView<RestResource, Object> m =
+ (RestModifyView<RestResource, Object>) viewData.view;
- if (viewData.view instanceof RestReadView<?> && isRead(req)) {
- response =
- invokeRestReadViewWithRetry(
- req,
- traceContext,
- viewData,
- (RestReadView<RestResource>) viewData.view,
- rsrc);
- } else if (viewData.view instanceof RestModifyView<?, ?>) {
- RestModifyView<RestResource, Object> m =
- (RestModifyView<RestResource, Object>) viewData.view;
+ Type type = inputType(m);
+ inputRequestBody = parseRequest(req, type);
+ response =
+ invokeRestModifyViewWithRetry(
+ req, traceContext, viewData, m, rsrc, inputRequestBody);
- Type type = inputType(m);
- inputRequestBody = parseRequest(req, type);
- response =
- invokeRestModifyViewWithRetry(
- req, traceContext, viewData, m, rsrc, inputRequestBody);
-
- if (inputRequestBody instanceof RawInput) {
- try (InputStream is = req.getInputStream()) {
- ServletUtils.consumeRequestBody(is);
- }
+ if (inputRequestBody instanceof RawInput) {
+ try (InputStream is = req.getInputStream()) {
+ ServletUtils.consumeRequestBody(is);
}
- } else if (viewData.view instanceof RestCollectionCreateView<?, ?, ?>) {
- RestCollectionCreateView<RestResource, RestResource, Object> m =
- (RestCollectionCreateView<RestResource, RestResource, Object>) viewData.view;
+ }
+ } else if (viewData.view instanceof RestCollectionCreateView<?, ?, ?>) {
+ RestCollectionCreateView<RestResource, RestResource, Object> m =
+ (RestCollectionCreateView<RestResource, RestResource, Object>) viewData.view;
- Type type = inputType(m);
- inputRequestBody = parseRequest(req, type);
- response =
- invokeRestCollectionCreateViewWithRetry(
- req, traceContext, viewData, m, rsrc, path.get(0), inputRequestBody);
- if (inputRequestBody instanceof RawInput) {
- try (InputStream is = req.getInputStream()) {
- ServletUtils.consumeRequestBody(is);
- }
+ Type type = inputType(m);
+ inputRequestBody = parseRequest(req, type);
+ response =
+ invokeRestCollectionCreateViewWithRetry(
+ req, traceContext, viewData, m, rsrc, path.get(0), inputRequestBody);
+ if (inputRequestBody instanceof RawInput) {
+ try (InputStream is = req.getInputStream()) {
+ ServletUtils.consumeRequestBody(is);
}
- } else if (viewData.view instanceof RestCollectionDeleteMissingView<?, ?, ?>) {
- RestCollectionDeleteMissingView<RestResource, RestResource, Object> m =
- (RestCollectionDeleteMissingView<RestResource, RestResource, Object>)
- viewData.view;
+ }
+ } else if (viewData.view instanceof RestCollectionDeleteMissingView<?, ?, ?>) {
+ RestCollectionDeleteMissingView<RestResource, RestResource, Object> m =
+ (RestCollectionDeleteMissingView<RestResource, RestResource, Object>) viewData.view;
- Type type = inputType(m);
- inputRequestBody = parseRequest(req, type);
- response =
- invokeRestCollectionDeleteMissingViewWithRetry(
- req, traceContext, viewData, m, rsrc, path.get(0), inputRequestBody);
- if (inputRequestBody instanceof RawInput) {
- try (InputStream is = req.getInputStream()) {
- ServletUtils.consumeRequestBody(is);
- }
+ Type type = inputType(m);
+ inputRequestBody = parseRequest(req, type);
+ response =
+ invokeRestCollectionDeleteMissingViewWithRetry(
+ req, traceContext, viewData, m, rsrc, path.get(0), inputRequestBody);
+ if (inputRequestBody instanceof RawInput) {
+ try (InputStream is = req.getInputStream()) {
+ ServletUtils.consumeRequestBody(is);
}
- } else if (viewData.view instanceof RestCollectionModifyView<?, ?, ?>) {
- RestCollectionModifyView<RestResource, RestResource, Object> m =
- (RestCollectionModifyView<RestResource, RestResource, Object>) viewData.view;
+ }
+ } else if (viewData.view instanceof RestCollectionModifyView<?, ?, ?>) {
+ RestCollectionModifyView<RestResource, RestResource, Object> m =
+ (RestCollectionModifyView<RestResource, RestResource, Object>) viewData.view;
- Type type = inputType(m);
- inputRequestBody = parseRequest(req, type);
- response =
- invokeRestCollectionModifyViewWithRetry(
- req, traceContext, viewData, m, rsrc, inputRequestBody);
- if (inputRequestBody instanceof RawInput) {
- try (InputStream is = req.getInputStream()) {
- ServletUtils.consumeRequestBody(is);
- }
+ Type type = inputType(m);
+ inputRequestBody = parseRequest(req, type);
+ response =
+ invokeRestCollectionModifyViewWithRetry(
+ req, traceContext, viewData, m, rsrc, inputRequestBody);
+ if (inputRequestBody instanceof RawInput) {
+ try (InputStream is = req.getInputStream()) {
+ ServletUtils.consumeRequestBody(is);
}
- } else {
- throw new ResourceNotFoundException();
- }
- String isUpdatedRefEnabled = req.getHeader(X_GERRIT_UPDATED_REF_ENABLED);
- if (!Strings.isNullOrEmpty(isUpdatedRefEnabled)
- && Boolean.valueOf(isUpdatedRefEnabled)) {
- setXGerritUpdatedRefResponseHeaders(req, res);
- }
-
- if (response instanceof Response.Redirect) {
- CacheHeaders.setNotCacheable(res);
- String location = ((Response.Redirect) response).location();
- res.sendRedirect(location);
- logger.atFinest().log("REST call redirected to: %s", location);
- return;
- } else if (response instanceof Response.Accepted) {
- CacheHeaders.setNotCacheable(res);
- res.setStatus(response.statusCode());
- res.setHeader(HttpHeaders.LOCATION, ((Response.Accepted) response).location());
- logger.atFinest().log("REST call succeeded: %d", response.statusCode());
- return;
- }
-
- statusCode = response.statusCode();
- response.headers().forEach((k, v) -> res.setHeader(k, v));
- configureCaching(req, res, rsrc, response.caching());
- res.setStatus(statusCode);
- logger.atFinest().log("REST call succeeded: %d", statusCode);
- }
-
- if (response != Response.none()) {
- Object value = Response.unwrap(response);
- if (value instanceof BinaryResult) {
- responseBytes = replyBinaryResult(req, res, (BinaryResult) value);
- } else {
- responseBytes = replyJson(req, res, false, qp.config(), value);
- }
- }
- }
- } catch (MalformedJsonException | JsonParseException e) {
- cause = Optional.of(e);
- logger.atFine().withCause(e).log("REST call failed on JSON parsing");
- responseBytes =
- replyError(
- req, res, statusCode = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request", e);
- } catch (BadRequestException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req, res, statusCode = SC_BAD_REQUEST, messageOr(e, "Bad Request"), e.caching(), e);
- } catch (AuthException e) {
- cause = Optional.of(e);
-
- StringBuilder messageBuilder = new StringBuilder(messageOr(e, "Forbidden"));
- globals
- .aclInfoController
- .getAclInfoMessage()
- .ifPresent(aclInfo -> messageBuilder.append("\n\n").append(aclInfo));
-
- responseBytes =
- replyError(
- req, res, statusCode = SC_FORBIDDEN, messageBuilder.toString(), e.caching(), e);
- } catch (AmbiguousViewException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(req, res, statusCode = SC_NOT_FOUND, messageOr(e, "Ambiguous"), e);
- } catch (ResourceNotFoundException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req, res, statusCode = SC_NOT_FOUND, messageOr(e, "Not Found"), e.caching(), e);
- } catch (MethodNotAllowedException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req,
- res,
- statusCode = SC_METHOD_NOT_ALLOWED,
- messageOr(e, "Method Not Allowed"),
- e.caching(),
- e);
- } catch (ResourceConflictException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req, res, statusCode = SC_CONFLICT, messageOr(e, "Conflict"), e.caching(), e);
- } catch (PreconditionFailedException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req,
- res,
- statusCode = SC_PRECONDITION_FAILED,
- messageOr(e, "Precondition Failed"),
- e.caching(),
- e);
- } catch (UnprocessableEntityException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req,
- res,
- statusCode = SC_UNPROCESSABLE_ENTITY,
- messageOr(e, "Unprocessable Entity"),
- e.caching(),
- e);
- } catch (NotImplementedException e) {
- cause = Optional.of(e);
- logger.atSevere().withCause(e).log("Error in %s %s", req.getMethod(), uriForLogging(req));
- responseBytes =
- replyError(
- req, res, statusCode = SC_NOT_IMPLEMENTED, messageOr(e, "Not Implemented"), e);
- } catch (QuotaException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(
- req,
- res,
- statusCode = SC_TOO_MANY_REQUESTS,
- messageOr(e, "Quota limit reached"),
- e.caching(),
- e);
- } catch (InvalidDeadlineException e) {
- cause = Optional.of(e);
- responseBytes =
- replyError(req, res, statusCode = SC_BAD_REQUEST, messageOr(e, "Bad Request"), e);
- } catch (Exception e) {
- cause = Optional.of(e);
-
- Optional<RequestCancelledException> requestCancelledException =
- RequestCancelledException.getFromCausalChain(e);
- if (requestCancelledException.isPresent()) {
- RequestStateProvider.Reason cancellationReason =
- requestCancelledException.get().getCancellationReason();
- globals.cancellationMetrics.countCancelledRequest(
- RequestInfo.RequestType.REST, requestUri, cancellationReason);
- statusCode = getCancellationStatusCode(cancellationReason);
- responseBytes =
- replyError(
- req, res, statusCode, getCancellationMessage(requestCancelledException.get()), e);
- } else {
- statusCode = SC_INTERNAL_SERVER_ERROR;
-
- Optional<ExceptionHook.Status> status = getStatus(e);
- statusCode =
- status.map(ExceptionHook.Status::statusCode).orElse(SC_INTERNAL_SERVER_ERROR);
-
- if (res.isCommitted()) {
- responseBytes = 0;
- if (statusCode == SC_INTERNAL_SERVER_ERROR) {
- logger.atSevere().withCause(e).log(
- "Error in %s %s, response already committed",
- req.getMethod(), uriForLogging(req));
- } else {
- logger.atWarning().log(
- "Response for %s %s already committed, wanted to set status %d",
- req.getMethod(), uriForLogging(req), statusCode);
}
} else {
- res.reset();
- TraceContext.getTraceIds().forEach(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
+ throw new ResourceNotFoundException();
+ }
+ String isUpdatedRefEnabled = req.getHeader(X_GERRIT_UPDATED_REF_ENABLED);
+ if (!Strings.isNullOrEmpty(isUpdatedRefEnabled) && Boolean.valueOf(isUpdatedRefEnabled)) {
+ setXGerritUpdatedRefResponseHeaders(req, res);
+ }
- if (status.isPresent()) {
- responseBytes = reply(req, res, e, status.get(), getUserMessages(e));
- } else {
- responseBytes =
- replyInternalServerError(req, res, e, getViewName(viewData), getUserMessages(e));
- }
+ if (response instanceof Response.Redirect) {
+ CacheHeaders.setNotCacheable(res);
+ String location = ((Response.Redirect) response).location();
+ res.sendRedirect(location);
+ logger.atFinest().log("REST call redirected to: %s", location);
+ return;
+ } else if (response instanceof Response.Accepted) {
+ CacheHeaders.setNotCacheable(res);
+ res.setStatus(response.statusCode());
+ res.setHeader(HttpHeaders.LOCATION, ((Response.Accepted) response).location());
+ logger.atFinest().log("REST call succeeded: %d", response.statusCode());
+ return;
+ }
+
+ statusCode = response.statusCode();
+ response.headers().forEach((k, v) -> res.setHeader(k, v));
+ configureCaching(req, res, rsrc, response.caching());
+ res.setStatus(statusCode);
+ logger.atFinest().log("REST call succeeded: %d", statusCode);
+ }
+
+ if (response != Response.none()) {
+ Object value = Response.unwrap(response);
+ if (value instanceof BinaryResult) {
+ responseBytes = replyBinaryResult(req, res, (BinaryResult) value);
+ } else {
+ responseBytes = replyJson(req, res, false, qp.config(), value);
}
}
- } finally {
- String metric = getViewName(viewData);
- String formattedCause = cause.map(globals.retryHelper::formatCause).orElse("_none");
- globals.metrics.count.increment(metric);
- if (statusCode >= SC_BAD_REQUEST) {
- globals.metrics.errorCount.increment(metric, statusCode, formattedCause);
- }
- if (responseBytes != -1) {
- globals.metrics.responseBytes.record(metric, responseBytes);
- }
- globals.metrics.serverLatency.record(
- metric, System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
- globals.auditService.dispatch(
- new ExtendedHttpAuditEvent(
- sessionId,
- currentUser,
- req,
- auditStartTs,
- qp != null ? qp.params() : ImmutableListMultimap.of(),
- inputRequestBody,
- statusCode,
- response,
- rsrc,
- viewData == null ? null : viewData.view));
}
+ } catch (MalformedJsonException | JsonParseException e) {
+ cause = Optional.of(e);
+ logger.atFine().withCause(e).log("REST call failed on JSON parsing");
+ responseBytes =
+ replyError(
+ req, res, statusCode = SC_BAD_REQUEST, "Invalid " + JSON_TYPE + " in request", e);
+ } catch (BadRequestException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req, res, statusCode = SC_BAD_REQUEST, messageOr(e, "Bad Request"), e.caching(), e);
+ } catch (AuthException e) {
+ cause = Optional.of(e);
+
+ StringBuilder messageBuilder = new StringBuilder(messageOr(e, "Forbidden"));
+ globals
+ .aclInfoController
+ .getAclInfoMessage()
+ .ifPresent(aclInfo -> messageBuilder.append("\n\n").append(aclInfo));
+
+ responseBytes =
+ replyError(
+ req, res, statusCode = SC_FORBIDDEN, messageBuilder.toString(), e.caching(), e);
+ } catch (AmbiguousViewException e) {
+ cause = Optional.of(e);
+ responseBytes = replyError(req, res, statusCode = SC_NOT_FOUND, messageOr(e, "Ambiguous"), e);
+ } catch (ResourceNotFoundException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req, res, statusCode = SC_NOT_FOUND, messageOr(e, "Not Found"), e.caching(), e);
+ } catch (MethodNotAllowedException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req,
+ res,
+ statusCode = SC_METHOD_NOT_ALLOWED,
+ messageOr(e, "Method Not Allowed"),
+ e.caching(),
+ e);
+ } catch (ResourceConflictException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(req, res, statusCode = SC_CONFLICT, messageOr(e, "Conflict"), e.caching(), e);
+ } catch (PreconditionFailedException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req,
+ res,
+ statusCode = SC_PRECONDITION_FAILED,
+ messageOr(e, "Precondition Failed"),
+ e.caching(),
+ e);
+ } catch (UnprocessableEntityException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req,
+ res,
+ statusCode = SC_UNPROCESSABLE_ENTITY,
+ messageOr(e, "Unprocessable Entity"),
+ e.caching(),
+ e);
+ } catch (NotImplementedException e) {
+ cause = Optional.of(e);
+ logger.atSevere().withCause(e).log("Error in %s %s", req.getMethod(), uriForLogging(req));
+ responseBytes =
+ replyError(req, res, statusCode = SC_NOT_IMPLEMENTED, messageOr(e, "Not Implemented"), e);
+ } catch (QuotaException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(
+ req,
+ res,
+ statusCode = SC_TOO_MANY_REQUESTS,
+ messageOr(e, "Quota limit reached"),
+ e.caching(),
+ e);
+ } catch (InvalidDeadlineException e) {
+ cause = Optional.of(e);
+ responseBytes =
+ replyError(req, res, statusCode = SC_BAD_REQUEST, messageOr(e, "Bad Request"), e);
+ } catch (Exception e) {
+ cause = Optional.of(e);
+
+ Optional<RequestCancelledException> requestCancelledException =
+ RequestCancelledException.getFromCausalChain(e);
+ if (requestCancelledException.isPresent()) {
+ RequestStateProvider.Reason cancellationReason =
+ requestCancelledException.get().getCancellationReason();
+ globals.cancellationMetrics.countCancelledRequest(
+ RequestInfo.RequestType.REST, requestUri, cancellationReason);
+ statusCode = getCancellationStatusCode(cancellationReason);
+ responseBytes =
+ replyError(
+ req, res, statusCode, getCancellationMessage(requestCancelledException.get()), e);
+ } else {
+ statusCode = SC_INTERNAL_SERVER_ERROR;
+
+ Optional<ExceptionHook.Status> status = getStatus(e);
+ statusCode = status.map(ExceptionHook.Status::statusCode).orElse(SC_INTERNAL_SERVER_ERROR);
+
+ if (res.isCommitted()) {
+ responseBytes = 0;
+ if (statusCode == SC_INTERNAL_SERVER_ERROR) {
+ logger.atSevere().withCause(e).log(
+ "Error in %s %s, response already committed", req.getMethod(), uriForLogging(req));
+ } else {
+ logger.atWarning().log(
+ "Response for %s %s already committed, wanted to set status %d",
+ req.getMethod(), uriForLogging(req), statusCode);
+ }
+ } else {
+ res.reset();
+ TraceContext.getTraceIds().forEach(traceId -> res.addHeader(X_GERRIT_TRACE, traceId));
+
+ if (status.isPresent()) {
+ responseBytes = reply(req, res, e, status.get(), getUserMessages(e));
+ } else {
+ responseBytes =
+ replyInternalServerError(req, res, e, getViewName(viewData), getUserMessages(e));
+ }
+ }
+ }
+ } finally {
+ String metric = getViewName(viewData);
+ String formattedCause = cause.map(globals.retryHelper::formatCause).orElse("_none");
+ globals.metrics.count.increment(metric);
+ if (statusCode >= SC_BAD_REQUEST) {
+ globals.metrics.errorCount.increment(metric, statusCode, formattedCause);
+ }
+ if (responseBytes != -1) {
+ globals.metrics.responseBytes.record(metric, responseBytes);
+ }
+ globals.metrics.serverLatency.record(
+ metric, System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
+ globals.auditService.dispatch(
+ new ExtendedHttpAuditEvent(
+ sessionId,
+ currentUser,
+ req,
+ auditStartTs,
+ qp != null ? qp.params() : ImmutableListMultimap.of(),
+ inputRequestBody,
+ statusCode,
+ response,
+ rsrc,
+ viewData == null ? null : viewData.view));
}
}
@@ -1575,43 +1568,6 @@
return parameterNames;
}
- private TraceContext enableTracing(HttpServletRequest req, HttpServletResponse res) {
- // There are 2 ways to enable tracing for REST calls:
- // 1. by using the 'trace' or 'trace=<trace-id>' request parameter
- // 2. by setting the 'X-Gerrit-Trace:' or 'X-Gerrit-Trace:<trace-id>' header
- String traceValueFromHeader = req.getHeader(X_GERRIT_TRACE);
- String traceValueFromRequestParam = req.getParameter(ParameterParser.TRACE_PARAMETER);
- boolean forceLogging = traceValueFromHeader != null || traceValueFromRequestParam != null;
-
- // Check whether no trace ID, one trace ID or 2 different trace IDs have been specified.
- String traceId1;
- String traceId2;
- if (!Strings.isNullOrEmpty(traceValueFromHeader)) {
- traceId1 = traceValueFromHeader;
- if (!Strings.isNullOrEmpty(traceValueFromRequestParam)
- && !traceValueFromHeader.equals(traceValueFromRequestParam)) {
- traceId2 = traceValueFromRequestParam;
- } else {
- traceId2 = null;
- }
- } else {
- traceId1 = Strings.emptyToNull(traceValueFromRequestParam);
- traceId2 = null;
- }
-
- // Use the first trace ID to start tracing. If this trace ID is null, a trace ID will be
- // generated.
- TraceContext traceContext =
- TraceContext.newTrace(
- forceLogging, traceId1, (tagName, traceId) -> res.setHeader(X_GERRIT_TRACE, traceId));
- // If a second trace ID was specified, add a tag for it as well.
- if (traceId2 != null) {
- traceContext.addTag(RequestId.Type.TRACE_ID, traceId2);
- res.addHeader(X_GERRIT_TRACE, traceId2);
- }
- return traceContext;
- }
-
private RequestInfo createRequestInfo(
TraceContext traceContext, HttpServletRequest req, String requestUri, List<IdString> path) {
RequestInfo.Builder requestInfo =
diff --git a/java/com/google/gerrit/launcher/GerritLauncher.java b/java/com/google/gerrit/launcher/GerritLauncher.java
index 55e79f3..53f4af9 100644
--- a/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -717,7 +717,7 @@
} else if ("jar".equals(u.getProtocol())) {
String p = u.getPath();
try {
- u = new URL(p.substring(0, p.indexOf('!')));
+ u = URI.create(p.substring(0, p.indexOf('!'))).toURL();
} catch (MalformedURLException e) {
FileNotFoundException fnfe = new FileNotFoundException("Not a valid jar file: " + u);
fnfe.initCause(e);
diff --git a/java/com/google/gerrit/pgm/util/ProxyUtil.java b/java/com/google/gerrit/pgm/util/ProxyUtil.java
index c2c1141..c765f95 100644
--- a/java/com/google/gerrit/pgm/util/ProxyUtil.java
+++ b/java/com/google/gerrit/pgm/util/ProxyUtil.java
@@ -39,6 +39,7 @@
import com.google.common.base.Strings;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import org.eclipse.jgit.util.CachedAuthenticator;
@@ -59,7 +60,7 @@
return;
}
- final URL u = new URL(!s.contains("://") ? "http://" + s : s);
+ final URL u = URI.create(!s.contains("://") ? "http://" + s : s).toURL();
if (!"http".equals(u.getProtocol())) {
throw new MalformedURLException("Invalid http_proxy: " + s + ": Only http supported.");
}
diff --git a/java/com/google/gerrit/server/ExceptionHook.java b/java/com/google/gerrit/server/ExceptionHook.java
index 3604d2b..501843c 100644
--- a/java/com/google/gerrit/server/ExceptionHook.java
+++ b/java/com/google/gerrit/server/ExceptionHook.java
@@ -138,8 +138,8 @@
* <p>If multiple exception hooks return a value from this method, the value from exception hook
* that is registered first is used.
*
- * <p>{@link #getUserMessages(Throwable, ImmutableSet<String>)} allows to define which additional
- * messages should be included into the body of the HTTP response.
+ * <p>{@link #getUserMessages(Throwable, ImmutableSet)} allows to define which additional messages
+ * should be included into the body of the HTTP response.
*
* @param throwable throwable that was thrown while executing an operation
* @return HTTP status that should be returned to the user, {@link Optional#empty()} if the
diff --git a/java/com/google/gerrit/server/IdentifiedUser.java b/java/com/google/gerrit/server/IdentifiedUser.java
index b069e39..d5cb87d 100644
--- a/java/com/google/gerrit/server/IdentifiedUser.java
+++ b/java/com/google/gerrit/server/IdentifiedUser.java
@@ -44,7 +44,7 @@
import com.google.inject.util.Providers;
import java.net.MalformedURLException;
import java.net.SocketAddress;
-import java.net.URL;
+import java.net.URI;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Optional;
@@ -474,7 +474,7 @@
String host;
if (canonicalUrl.get() != null) {
try {
- host = new URL(canonicalUrl.get()).getHost();
+ host = URI.create(canonicalUrl.get()).toURL().getHost();
} catch (MalformedURLException e) {
host = SystemReader.getInstance().getHostname();
}
diff --git a/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java b/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java
index b2e80d7..9dfd049 100644
--- a/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java
+++ b/java/com/google/gerrit/server/config/GerritInstanceNameProvider.java
@@ -19,7 +19,7 @@
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.util.SystemReader;
@@ -51,7 +51,7 @@
private static String extractInstanceName(String canonicalUrl) {
if (canonicalUrl != null) {
try {
- return new URL(canonicalUrl).getHost();
+ return URI.create(canonicalUrl).toURL().getHost();
} catch (MalformedURLException e) {
// Try something else.
}
diff --git a/java/com/google/gerrit/server/config/GitwebConfig.java b/java/com/google/gerrit/server/config/GitwebConfig.java
index edb3bb3..a74e551 100644
--- a/java/com/google/gerrit/server/config/GitwebConfig.java
+++ b/java/com/google/gerrit/server/config/GitwebConfig.java
@@ -38,6 +38,7 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.net.MalformedURLException;
+import java.net.URI;
import java.net.URL;
import org.eclipse.jgit.lib.Config;
@@ -203,7 +204,7 @@
} else {
String baseGerritUrl;
if (gerritUrl != null) {
- URL u = new URL(gerritUrl);
+ URL u = URI.create(gerritUrl).toURL();
baseGerritUrl = u.getPath();
} else {
baseGerritUrl = "/";
diff --git a/java/com/google/gerrit/server/git/DelegateRefDatabase.java b/java/com/google/gerrit/server/git/DelegateRefDatabase.java
index 3dbc881..a8b1bb9 100644
--- a/java/com/google/gerrit/server/git/DelegateRefDatabase.java
+++ b/java/com/google/gerrit/server/git/DelegateRefDatabase.java
@@ -114,13 +114,13 @@
@Override
public ReflogReader getReflogReader(String refName) throws IOException {
- return delegate.getReflogReader(refName);
+ return delegate.getRefDatabase().getReflogReader(refName);
}
@Override
@NonNull
public ReflogReader getReflogReader(@NonNull Ref ref) throws IOException {
- return delegate.getReflogReader(ref);
+ return delegate.getRefDatabase().getReflogReader(ref);
}
@Override
diff --git a/java/com/google/gerrit/server/git/DelegateRepository.java b/java/com/google/gerrit/server/git/DelegateRepository.java
index 8cedc89..ce166ef 100644
--- a/java/com/google/gerrit/server/git/DelegateRepository.java
+++ b/java/com/google/gerrit/server/git/DelegateRepository.java
@@ -112,7 +112,7 @@
@Override
public ReflogReader getReflogReader(String refName) throws IOException {
- return delegate.getReflogReader(refName);
+ return delegate.getRefDatabase().getReflogReader(refName);
}
@SuppressWarnings("rawtypes")
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 9696e12..392f2ae 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -74,7 +74,7 @@
import com.google.inject.Singleton;
import java.io.IOException;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -991,7 +991,7 @@
private static String getGerritHost(String canonicalWebUrl) {
if (canonicalWebUrl != null) {
try {
- return new URL(canonicalWebUrl).getHost();
+ return URI.create(canonicalWebUrl).toURL().getHost();
} catch (MalformedURLException ignored) {
logger.atWarning().log(
"configured canonical web URL is invalid, using system default: %s",
diff --git a/java/com/google/gerrit/server/mail/EmailFactories.java b/java/com/google/gerrit/server/mail/EmailFactories.java
index 6b0bcf0..cb9d541 100644
--- a/java/com/google/gerrit/server/mail/EmailFactories.java
+++ b/java/com/google/gerrit/server/mail/EmailFactories.java
@@ -17,6 +17,7 @@
import com.google.gerrit.entities.Address;
import com.google.gerrit.entities.Change;
import com.google.gerrit.entities.Project;
+import com.google.gerrit.entities.Project.NameKey;
import com.google.gerrit.entities.SubmitRequirement;
import com.google.gerrit.entities.SubmitRequirementResult;
import com.google.gerrit.extensions.client.ChangeKind;
diff --git a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
index d0d380a..132fdc9 100644
--- a/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
+++ b/java/com/google/gerrit/server/mail/send/OutgoingEmail.java
@@ -46,7 +46,7 @@
import com.google.template.soy.data.SanitizedContent;
import com.google.template.soy.jbcsrc.api.SoySauce;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
@@ -448,7 +448,7 @@
Optional<String> gerritUrl = args.urlFormatter.get().getWebUrl();
if (gerritUrl.isPresent()) {
try {
- return new URL(gerritUrl.get()).getHost();
+ return URI.create(gerritUrl.get()).toURL().getHost();
} catch (MalformedURLException e) {
// Try something else.
}
diff --git a/java/com/google/gerrit/server/plugins/InstallPlugin.java b/java/com/google/gerrit/server/plugins/InstallPlugin.java
index a79a5a6..a1884db 100644
--- a/java/com/google/gerrit/server/plugins/InstallPlugin.java
+++ b/java/com/google/gerrit/server/plugins/InstallPlugin.java
@@ -32,7 +32,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.net.URL;
+import java.net.URI;
import java.util.zip.ZipException;
@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
@@ -88,7 +88,7 @@
return input.raw.getInputStream();
}
try {
- return new URL(input.url).openStream();
+ return URI.create(input.url).toURL().openStream();
} catch (IOException e) {
throw new BadRequestException(e.getMessage());
}
diff --git a/java/com/google/gerrit/server/project/ProjectCacheWarmer.java b/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
index 8794f66..4fec2ab 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheWarmer.java
@@ -45,32 +45,35 @@
public void start() {
int cpus = Runtime.getRuntime().availableProcessors();
if (config.getBoolean("cache", "projects", "loadOnStartup", false)) {
- ExecutorService pool =
- new LoggingContextAwareExecutorService(
- new ScheduledThreadPoolExecutor(
- config.getInt("cache", "projects", "loadThreads", cpus),
- new ThreadFactoryBuilder().setNameFormat("ProjectCacheLoader-%d").build()));
Thread scheduler =
new Thread(
() -> {
- for (Project.NameKey name : cache.all()) {
- pool.execute(
- () -> {
- Optional<ProjectState> project = cache.get(name);
- if (!project.isPresent()) {
- throw new IllegalStateException(
- "race while traversing projects. got "
- + name
- + " when loading all projects, but can't load it now");
- }
- });
- }
- pool.shutdown();
- try {
- pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
- logger.atInfo().log("Finished loading project cache");
- } catch (InterruptedException e) {
- logger.atWarning().log("Interrupted while waiting for project cache to load");
+ try (ExecutorService pool =
+ new LoggingContextAwareExecutorService(
+ new ScheduledThreadPoolExecutor(
+ config.getInt("cache", "projects", "loadThreads", cpus),
+ new ThreadFactoryBuilder()
+ .setNameFormat("ProjectCacheLoader-%d")
+ .build()))) {
+ for (Project.NameKey name : cache.all()) {
+ pool.execute(
+ () -> {
+ Optional<ProjectState> project = cache.get(name);
+ if (!project.isPresent()) {
+ throw new IllegalStateException(
+ "race while traversing projects. got "
+ + name
+ + " when loading all projects, but can't load it now");
+ }
+ });
+ }
+ pool.shutdown();
+ try {
+ pool.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
+ logger.atInfo().log("Finished loading project cache");
+ } catch (InterruptedException e) {
+ logger.atWarning().log("Interrupted while waiting for project cache to load");
+ }
}
});
scheduler.setName("ProjectCacheWarmer");
diff --git a/java/com/google/gerrit/server/restapi/change/ApplyProvidedFix.java b/java/com/google/gerrit/server/restapi/change/ApplyProvidedFix.java
index be1bced..a8e46b3 100644
--- a/java/com/google/gerrit/server/restapi/change/ApplyProvidedFix.java
+++ b/java/com/google/gerrit/server/restapi/change/ApplyProvidedFix.java
@@ -140,9 +140,9 @@
*
* <p>The method creates CommitModification by applying {@code fixReplacements} to the {@code
* basePatchSetForFix}. If the {@code targetPatchSetForFix} is different from the {@code
- * basePatchSetForFix}, CommitModification is created from the {@link PatchApplier.Result}, after
- * applying the patch generated from {@code basePatchSetForFix} to the {@code
- * targetPatchSetForFix}.
+ * basePatchSetForFix}, CommitModification is created from the {@link
+ * org.eclipse.jgit.patch.PatchApplier.Result}, after applying the patch generated from {@code
+ * basePatchSetForFix} to the {@code targetPatchSetForFix}.
*
* <p>Note: if there is a fix for a commit message and commit messages are different in {@code
* basePatchSetForFix} and {@code targetPatchSetForFix}, the method can't move the fix to the
diff --git a/java/com/google/gerrit/server/restapi/project/GetReflog.java b/java/com/google/gerrit/server/restapi/project/GetReflog.java
index 967b3c5..6016abc 100644
--- a/java/com/google/gerrit/server/restapi/project/GetReflog.java
+++ b/java/com/google/gerrit/server/restapi/project/GetReflog.java
@@ -100,7 +100,7 @@
try (Repository repo = repoManager.openRepository(rsrc.getNameKey())) {
ReflogReader r;
try {
- r = repo.getReflogReader(rsrc.getRef());
+ r = repo.getRefDatabase().getReflogReader(rsrc.getRef());
} catch (UnsupportedOperationException e) {
String msg = "reflog not supported on repo " + rsrc.getNameKey().get();
logger.atSevere().log("%s", msg);
diff --git a/java/com/google/gerrit/sshd/NoShell.java b/java/com/google/gerrit/sshd/NoShell.java
index ffac946..152b272 100644
--- a/java/com/google/gerrit/sshd/NoShell.java
+++ b/java/com/google/gerrit/sshd/NoShell.java
@@ -26,7 +26,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import org.apache.sshd.common.io.IoInputStream;
import org.apache.sshd.common.io.IoOutputStream;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -209,7 +209,7 @@
String url = urlProvider.get();
if (url != null) {
try {
- return new URL(url).getHost();
+ return URI.create(url).toURL().getHost();
} catch (MalformedURLException e) {
// Ignored
}
diff --git a/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java b/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
index cfb47f7..5d2bb4b 100644
--- a/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
+++ b/java/com/google/gerrit/sshd/commands/PluginInstallCommand.java
@@ -23,7 +23,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import java.nio.file.Files;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@@ -74,7 +74,7 @@
}
} else {
try {
- data = new URL(source).openStream();
+ data = URI.create(source).toURL().openStream();
} catch (MalformedURLException e) {
throw die("invalid url " + source, e);
} catch (IOException e) {
diff --git a/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java b/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
index 8395772..add21c2 100644
--- a/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetLoggingLevelCommand.java
@@ -24,7 +24,7 @@
import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.SshCommand;
import java.net.MalformedURLException;
-import java.net.URL;
+import java.net.URI;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
@@ -82,7 +82,7 @@
if (Strings.isNullOrEmpty(path)) {
PropertyConfigurator.configure(Loader.getResource(LOG_CONFIGURATION));
} else {
- PropertyConfigurator.configure(new URL(path));
+ PropertyConfigurator.configure(URI.create(path).toURL());
}
}
diff --git a/javatests/com/google/gerrit/acceptance/GitRepositoryReferenceCountingManagerIT.java b/javatests/com/google/gerrit/acceptance/GitRepositoryReferenceCountingManagerIT.java
index 3108238..b7da25c 100644
--- a/javatests/com/google/gerrit/acceptance/GitRepositoryReferenceCountingManagerIT.java
+++ b/javatests/com/google/gerrit/acceptance/GitRepositoryReferenceCountingManagerIT.java
@@ -34,11 +34,11 @@
}
}
- @Test(expected = AssertionError.class)
+ @Test()
@SuppressWarnings("resource")
public void shouldFailTestWhenRepositoryIsLeftOpen() throws Exception {
Repository unused = repoManager.openRepository(project);
- afterTest();
+ assertThrows(AssertionError.class, this::afterTest);
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/OutgoingEmailIT.java b/javatests/com/google/gerrit/acceptance/OutgoingEmailIT.java
index 7b21780..b0817fe 100644
--- a/javatests/com/google/gerrit/acceptance/OutgoingEmailIT.java
+++ b/javatests/com/google/gerrit/acceptance/OutgoingEmailIT.java
@@ -26,7 +26,7 @@
import com.google.gerrit.extensions.api.changes.ReviewerInput;
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.testing.FakeEmailSender;
-import java.net.URL;
+import java.net.URI;
import org.eclipse.jgit.lib.Repository;
import org.junit.Test;
@@ -135,6 +135,6 @@
// Each message-id must start with '<' and end with '>'. Also, it must contain no spaces and it
// must contain a '@'.
private String withPrefixAndSuffixForMessageId(String id) throws Exception {
- return "<" + id + "@" + new URL(canonicalWebUrl.get()).getHost() + ">";
+ return "<" + id + "@" + URI.create(canonicalWebUrl.get()).toURL().getHost() + ">";
}
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/RebaseChainOnBehalfOfUploaderIT.java b/javatests/com/google/gerrit/acceptance/api/change/RebaseChainOnBehalfOfUploaderIT.java
index b174d79..68d5a75 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/RebaseChainOnBehalfOfUploaderIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/RebaseChainOnBehalfOfUploaderIT.java
@@ -61,6 +61,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
+import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterLine;
@@ -1070,15 +1071,16 @@
gApi.changes().id(changeToBeRebased2.get()).rebaseChain(rebaseInput);
// The ref log for the patch set ref records the impersonated user aka the uploader.
- ReflogEntry patchSetRefLogEntry1 = repo.getReflogReader(patchSetRef1).getLastEntry();
+ RefDatabase refDb = repo.getRefDatabase();
+ ReflogEntry patchSetRefLogEntry1 = refDb.getReflogReader(patchSetRef1).getLastEntry();
assertThat(patchSetRefLogEntry1.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
- ReflogEntry patchSetRefLogEntry2 = repo.getReflogReader(patchSetRef2).getLastEntry();
+ ReflogEntry patchSetRefLogEntry2 = refDb.getReflogReader(patchSetRef2).getLastEntry();
assertThat(patchSetRefLogEntry2.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
// The ref log for the change meta ref records the impersonated user aka the uploader.
- ReflogEntry changeMetaRefLogEntry1 = repo.getReflogReader(changeMetaRef1).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry1 = refDb.getReflogReader(changeMetaRef1).getLastEntry();
assertThat(changeMetaRefLogEntry1.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
- ReflogEntry changeMetaRefLogEntry2 = repo.getReflogReader(changeMetaRef2).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry2 = refDb.getReflogReader(changeMetaRef2).getLastEntry();
assertThat(changeMetaRefLogEntry2.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
}
}
@@ -1132,15 +1134,16 @@
String combinedEmail = String.format("account-%s|account-%s@unknown", uploader1, uploader2);
// The ref log for the patch set ref records the impersonated user aka the uploader.
- ReflogEntry patchSetRefLogEntry1 = repo.getReflogReader(patchSetRef1).getLastEntry();
+ RefDatabase refDb = repo.getRefDatabase();
+ ReflogEntry patchSetRefLogEntry1 = refDb.getReflogReader(patchSetRef1).getLastEntry();
assertThat(patchSetRefLogEntry1.getWho().getEmailAddress()).isEqualTo(combinedEmail);
- ReflogEntry patchSetRefLogEntry2 = repo.getReflogReader(patchSetRef2).getLastEntry();
+ ReflogEntry patchSetRefLogEntry2 = refDb.getReflogReader(patchSetRef2).getLastEntry();
assertThat(patchSetRefLogEntry2.getWho().getEmailAddress()).isEqualTo(combinedEmail);
// The ref log for the change meta ref records the impersonated user aka the uploader.
- ReflogEntry changeMetaRefLogEntry1 = repo.getReflogReader(changeMetaRef1).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry1 = refDb.getReflogReader(changeMetaRef1).getLastEntry();
assertThat(changeMetaRefLogEntry1.getWho().getEmailAddress()).isEqualTo(combinedEmail);
- ReflogEntry changeMetaRefLogEntry2 = repo.getReflogReader(changeMetaRef2).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry2 = refDb.getReflogReader(changeMetaRef2).getLastEntry();
assertThat(changeMetaRefLogEntry2.getWho().getEmailAddress()).isEqualTo(combinedEmail);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/api/change/RebaseOnBehalfOfUploaderIT.java b/javatests/com/google/gerrit/acceptance/api/change/RebaseOnBehalfOfUploaderIT.java
index c711f4e..c6d74d1 100644
--- a/javatests/com/google/gerrit/acceptance/api/change/RebaseOnBehalfOfUploaderIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/change/RebaseOnBehalfOfUploaderIT.java
@@ -64,6 +64,7 @@
import com.google.inject.Inject;
import java.util.Collection;
import java.util.Optional;
+import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.ReflogEntry;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.FooterLine;
@@ -1088,11 +1089,12 @@
gApi.changes().id(changeToBeRebased.get()).rebase(rebaseInput);
// The ref log for the patch set ref records the impersonated user aka the uploader.
- ReflogEntry patchSetRefLogEntry = repo.getReflogReader(patchSetRef).getLastEntry();
+ RefDatabase refDb = repo.getRefDatabase();
+ ReflogEntry patchSetRefLogEntry = refDb.getReflogReader(patchSetRef).getLastEntry();
assertThat(patchSetRefLogEntry.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
// The ref log for the change meta ref records the impersonated user aka the uploader.
- ReflogEntry changeMetaRefLogEntry = repo.getReflogReader(changeMetaRef).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry = refDb.getReflogReader(changeMetaRef).getLastEntry();
assertThat(changeMetaRefLogEntry.getWho().getEmailAddress()).isEqualTo(uploaderEmail);
}
}
diff --git a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
index b9bbd96..d7007b4 100644
--- a/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/group/GroupsIT.java
@@ -568,7 +568,7 @@
assertThrows(AuthException.class, () -> gApi.groups().create(name("newGroup")));
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
@Test
diff --git a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 083910f..70807c9 100644
--- a/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/javatests/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -2075,7 +2075,7 @@
}
}
- // TODO(issue-15508): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
+ // TODO(issue-40014498): Migrate timestamp fields in *Info/*Input classes from type Timestamp to
// Instant
@SuppressWarnings("JdkObsolete")
private void assertPersonIdent(GitPerson gitPerson, PersonIdent expectedIdent) {
diff --git a/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
index 7de689d..5aac80d 100644
--- a/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/account/ImpersonationIT.java
@@ -151,7 +151,8 @@
.isEqualTo(changeNoteUtil.getAccountIdAsEmailAddress(impersonatedUser.id()));
// The ref log for the change meta ref records the impersonated user.
- ReflogEntry changeMetaRefLogEntry = repo.getReflogReader(changeMetaRef).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry =
+ repo.getRefDatabase().getReflogReader(changeMetaRef).getLastEntry();
assertThat(changeMetaRefLogEntry.getWho().getEmailAddress())
.isEqualTo(impersonatedUser.email());
}
@@ -556,7 +557,7 @@
// The ref log for the target branch records the impersonated user.
try (Repository repo = repoManager.openRepository(project)) {
ReflogEntry targetBranchRefLogEntry =
- repo.getReflogReader("refs/heads/master").getLastEntry();
+ repo.getRefDatabase().getReflogReader("refs/heads/master").getLastEntry();
assertThat(targetBranchRefLogEntry.getWho().getEmailAddress())
.isEqualTo(impersonatedUser.email());
}
@@ -592,13 +593,13 @@
try (Repository repo = repoManager.openRepository(project)) {
// The ref log for the patch set ref records the impersonated user.
ReflogEntry patchSetRefLogEntry =
- repo.getReflogReader(cd.currentPatchSet().refName()).getLastEntry();
+ repo.getRefDatabase().getReflogReader(cd.currentPatchSet().refName()).getLastEntry();
assertThat(patchSetRefLogEntry.getWho().getEmailAddress())
.isEqualTo(impersonatedUser.email());
// The ref log for the target branch records the impersonated user.
ReflogEntry targetBranchRefLogEntry =
- repo.getReflogReader("refs/heads/master").getLastEntry();
+ repo.getRefDatabase().getReflogReader("refs/heads/master").getLastEntry();
assertThat(targetBranchRefLogEntry.getWho().getEmailAddress())
.isEqualTo(impersonatedUser.email());
}
@@ -644,7 +645,8 @@
.isEqualTo(changeNoteUtil.getAccountIdAsEmailAddress(impersonatedUser.id()));
// The ref log for the change meta ref records the impersonated user.
- ReflogEntry changeMetaRefLogEntry = repo.getReflogReader(changeMetaRef).getLastEntry();
+ ReflogEntry changeMetaRefLogEntry =
+ repo.getRefDatabase().getReflogReader(changeMetaRef).getLastEntry();
assertThat(changeMetaRefLogEntry.getWho().getEmailAddress())
.isEqualTo(impersonatedUser.email());
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java
index 9e9ad6b..a4cf221 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java
@@ -20,7 +20,6 @@
import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allow;
import static com.google.gerrit.entities.RefNames.REFS_DASHBOARDS;
import static com.google.gerrit.server.restapi.project.DashboardsCollection.DEFAULT_DASHBOARD_NAME;
-import static org.apache.http.HttpStatus.SC_METHOD_NOT_ALLOWED;
import static org.apache.http.HttpStatus.SC_NOT_FOUND;
import com.google.common.collect.ImmutableList;
@@ -116,11 +115,6 @@
.expectedResponseCode(SC_NOT_FOUND)
.build(),
RestCall.get("/projects/%s/branches/%s/mergeable"),
- // The tests use DfsRepository which does not support getting the reflog.
- RestCall.builder(GET, "/projects/%s/branches/%s/reflog")
- .expectedResponseCode(SC_METHOD_NOT_ALLOWED)
- .expectedMessage("reflog not supported on")
- .build(),
RestCall.get("/projects/%s/branches/%s/validation-options"),
RestCall.get("/projects/%s/branches/%s/suggest_reviewers"),
diff --git a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
index 2bccc87..fb7a29a 100644
--- a/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/mail/MailProcessorIT.java
@@ -54,7 +54,7 @@
import com.google.gerrit.testing.TestCommentHelper;
import com.google.inject.Inject;
import com.google.inject.Module;
-import java.net.URL;
+import java.net.URI;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collection;
@@ -446,7 +446,8 @@
// ensure the message header contains a valid message id.
assertThat(((StringEmailHeader) message.headers().get("Message-ID")).getString())
- .containsMatch("<someid-REJECTION-HTML@" + new URL(canonicalWebUrl.get()).getHost() + ">");
+ .containsMatch(
+ "<someid-REJECTION-HTML@" + URI.create(canonicalWebUrl.get()).toURL().getHost() + ">");
}
@Test
diff --git a/javatests/com/google/gerrit/acceptance/server/project/ReflogIT.java b/javatests/com/google/gerrit/acceptance/server/project/ReflogIT.java
index 9093412..2d63f63 100644
--- a/javatests/com/google/gerrit/acceptance/server/project/ReflogIT.java
+++ b/javatests/com/google/gerrit/acceptance/server/project/ReflogIT.java
@@ -59,7 +59,7 @@
}
gApi.changes().id(id.get()).topic("foo");
- ReflogEntry last = repo.getReflogReader(changeMetaRef(id)).getLastEntry();
+ ReflogEntry last = repo.getRefDatabase().getReflogReader(changeMetaRef(id)).getLastEntry();
assertWithMessage("last RefLogEntry").that(last).isNotNull();
assertThat(last.getComment()).isEqualTo("restapi.change.PutTopic");
}
@@ -79,7 +79,7 @@
}
gApi.changes().id(id.get()).topic("foo");
- ReflogEntry last = repo.getReflogReader(changeMetaRef(id)).getLastEntry();
+ ReflogEntry last = repo.getRefDatabase().getReflogReader(changeMetaRef(id)).getLastEntry();
assertThat(last.getWho().getEmailAddress())
.isEqualTo(admin.username() + "|account-" + admin.id() + "@unknown");
}
@@ -98,7 +98,7 @@
}
gApi.changes().id(id.get()).topic("foo");
- ReflogEntry last = repo.getReflogReader(changeMetaRef(id)).getLastEntry();
+ ReflogEntry last = repo.getRefDatabase().getReflogReader(changeMetaRef(id)).getLastEntry();
assertThat(last.getWho().getEmailAddress()).isEqualTo(admin.email());
}
}
diff --git a/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java b/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
index 711fe05..b6b5dcc 100644
--- a/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
+++ b/javatests/com/google/gerrit/acceptance/ssh/StreamEventsIT.java
@@ -17,6 +17,7 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.gerrit.acceptance.WaitUtil.waitUntil;
import static com.google.gerrit.entities.Patch.PATCHSET_LEVEL;
+import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.common.base.Splitter;
import com.google.gerrit.acceptance.AbstractDaemonTest;
@@ -126,7 +127,7 @@
waitForEvent(() -> pollEventsContaining("ref-updated", "refs/draft-comments/").size() == 1);
}
- @Test(expected = InterruptedException.class)
+ @Test()
@GerritConfig(name = "event.stream-events.enableRefUpdatedEvents", value = "true")
@GerritConfig(name = "event.stream-events.enableBatchRefUpdatedEvents", value = "false")
@GerritConfig(name = "event.stream-events.enableDraftCommentEvents", value = "false")
@@ -135,7 +136,12 @@
draftReviewChange(PATCHSET_LEVEL, String.format("%s 1", TEST_REVIEW_DRAFT_COMMENT));
- waitForEvent(() -> pollEventsContaining("ref-updated", "refs/draft-comments/").size() == 1);
+ assertThrows(
+ InterruptedException.class,
+ () -> {
+ waitForEvent(
+ () -> pollEventsContaining("ref-updated", "refs/draft-comments/").size() == 1);
+ });
}
@Test
@@ -151,7 +157,7 @@
() -> pollEventsContaining("batch-ref-updated", "refs/draft-comments/").size() == 1);
}
- @Test(expected = InterruptedException.class)
+ @Test()
@GerritConfig(name = "event.stream-events.enableBatchRefUpdatedEvents", value = "true")
@GerritConfig(name = "event.stream-events.enableRefUpdatedEvents", value = "false")
@GerritConfig(name = "event.stream-events.enableDraftCommentEvents", value = "false")
@@ -160,7 +166,12 @@
draftReviewChange(PATCHSET_LEVEL, String.format("%s 1", TEST_REVIEW_DRAFT_COMMENT));
- waitForEvent(() -> pollEventsContaining("ref-updated", "refs/draft-comments/").size() == 1);
+ assertThrows(
+ InterruptedException.class,
+ () -> {
+ waitForEvent(
+ () -> pollEventsContaining("ref-updated", "refs/draft-comments/").size() == 1);
+ });
}
@Test
diff --git a/javatests/com/google/gerrit/server/git/RepoRefCacheTest.java b/javatests/com/google/gerrit/server/git/RepoRefCacheTest.java
index 75979a4..16d6a4a 100644
--- a/javatests/com/google/gerrit/server/git/RepoRefCacheTest.java
+++ b/javatests/com/google/gerrit/server/git/RepoRefCacheTest.java
@@ -265,7 +265,7 @@
@Override
public ReflogReader getReflogReader(String refName) throws IOException {
checkIsOpen();
- return repo.getReflogReader(refName);
+ return repo.getRefDatabase().getReflogReader(refName);
}
private void checkIsOpen() {
diff --git a/plugins/download-commands b/plugins/download-commands
index 09119a0..978e803 160000
--- a/plugins/download-commands
+++ b/plugins/download-commands
@@ -1 +1 @@
-Subproject commit 09119a065739a5921b7ad8eef75c996ae4043d8a
+Subproject commit 978e803c87416eb9e96236446b15b167017c0385
diff --git a/plugins/gitiles b/plugins/gitiles
index e6146ea..e5c66ff 160000
--- a/plugins/gitiles
+++ b/plugins/gitiles
@@ -1 +1 @@
-Subproject commit e6146eafd28d3776470f86b0d675964d56695779
+Subproject commit e5c66ffd3af9fdbcc4f98fb7c594850bb5f513c7
diff --git a/plugins/plugin-manager b/plugins/plugin-manager
index 2808425..ed7870e 160000
--- a/plugins/plugin-manager
+++ b/plugins/plugin-manager
@@ -1 +1 @@
-Subproject commit 2808425de3d91a319d7497e127af1336ca6692c0
+Subproject commit ed7870eb3c8b6e48511d0eb3bd54606927b46019
diff --git a/plugins/replication b/plugins/replication
index 729e562..a9f44a1 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 729e562946ae7357774c9e8572ef9052c15a6e9e
+Subproject commit a9f44a14c64efaa44afdf8f553a3b3211ef4342b
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index d205267..d3681a5 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -822,10 +822,32 @@
.header {
align-items: center;
background-color: var(--background-color-primary);
- border-bottom: 1px solid var(--border-color);
+ border-bottom: 2px solid var(--border-color);
display: flex;
padding: var(--spacing-s) var(--spacing-l);
}
+ .header.active {
+ border-color: var(--status-active);
+ }
+ .header.abandoned {
+ border-color: var(--status-abandoned);
+ }
+ .header.merged {
+ border-color: var(--status-merged);
+ }
+ .header.private {
+ border-color: var(--status-private);
+ }
+ .header.ready-to-submit {
+ border-color: var(--status-ready);
+ }
+ .header.wip {
+ border-color: var(--status-wip);
+ }
+ .header.merge-conflict,
+ .header.git-conflict {
+ border-color: var(--status-conflict);
+ }
.header.editMode {
background-color: var(--edit-mode-background-color);
}
@@ -2375,6 +2397,10 @@
// Private but used in tests.
computeHeaderClass() {
const classes = ['header'];
+ const status = this.computeChangeStatusChips()?.[0];
+ if (status) {
+ classes.push(status.toLowerCase());
+ }
if (this.editMode) {
classes.push('editMode');
}
diff --git a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
index 97fa267..00130fe 100644
--- a/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
+++ b/polygerrit-ui/app/elements/shared/gr-change-status/gr-change-status.ts
@@ -81,6 +81,7 @@
}
:host(.active) .chip {
background-color: var(--status-active);
+ --status-text-color: black;
color: var(--status-active);
}
:host(.ready-to-submit) .chip {
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
index 2913fc8..40ce039 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff-styles.ts
@@ -82,6 +82,15 @@
/* Needs z-index to appear above wrapped content, since it's inserted
into DOM before it. */
z-index: 120;
+ position: absolute;
+ }
+ gr-diff-element gr-selection-action-box slot[invisible] {
+ visibility: hidden;
+ }
+ gr-diff-element gr-selection-action-box gr-tooltip {
+ position: absolute;
+ width: 22ch;
+ cursor: pointer;
}
`;
diff --git a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
index 06c6768..9f08149 100644
--- a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
+++ b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
@@ -6,9 +6,8 @@
import '../../../elements/shared/gr-tooltip/gr-tooltip';
import {GrTooltip} from '../../../elements/shared/gr-tooltip/gr-tooltip';
import {fire} from '../../../utils/event-util';
-import {css, html, LitElement} from 'lit';
+import {html, LitElement} from 'lit';
import {customElement, property, query, state} from 'lit/decorators.js';
-import {sharedStyles} from '../../../styles/shared-styles';
declare global {
interface HTMLElementTagNameMap {
@@ -25,6 +24,10 @@
@query('#tooltip')
tooltip?: GrTooltip;
+ @state() private isSlotAssigned = false;
+
+ @query('slot') slotElement!: HTMLSlotElement;
+
@property({type: Boolean})
positionBelow = false;
@@ -43,32 +46,38 @@
this.addEventListener('mousedown', e => this.handleMouseDown(e));
}
- static override get styles() {
- return [
- sharedStyles,
- css`
- :host {
- cursor: pointer;
- font-family: var(--font-family);
- position: absolute;
- width: 20ch;
- }
- gr-tooltip[invisible] {
- visibility: hidden;
- }
- `,
- ];
+ override render() {
+ // We create the gr-tooltip anyway even if the slot is assigned so that
+ // we reuse the logic for positioning the tooltip (in placeAbove/Below).
+ return html`
+ <slot
+ name="selectionActionBox"
+ ?invisible=${this.invisible}
+ @slotchange=${this.handleSlotChange}
+ >
+ <gr-tooltip
+ id="tooltip"
+ text=${this.hoverCardText}
+ ?position-below=${this.positionBelow}
+ ></gr-tooltip>
+ </slot>
+ `;
}
- override render() {
- return html`
- <gr-tooltip
- id="tooltip"
- ?invisible=${this.invisible}
- text=${this.hoverCardText}
- ?position-below=${this.positionBelow}
- ></gr-tooltip>
- `;
+ private handleSlotChange() {
+ const assignedNodes = this.slotElement.assignedNodes({flatten: true});
+ this.isSlotAssigned = assignedNodes.length > 0;
+ }
+
+ /**
+ * The browser API for handling selection does not (yet) work for selection
+ * across multiple shadow DOM elements. So we are rendering gr-diff components
+ * into the light DOM instead of the shadow DOM by overriding this method,
+ * which was the recommended workaround by the lit team.
+ * See also https://github.com/WICG/webcomponents/issues/79.
+ */
+ override createRenderRoot() {
+ return this;
}
// TODO(b/315277651): This is very similar in purpose to gr-tooltip-content.
@@ -133,6 +142,9 @@
// visible for testing
handleMouseDown(e: MouseEvent) {
+ if (this.isSlotAssigned) {
+ return;
+ }
if (e.button !== 0) {
return;
} // 0 = main button
diff --git a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box_test.ts b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box_test.ts
index 5cc8409..9155e53 100644
--- a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box_test.ts
@@ -32,14 +32,13 @@
});
test('renders', () => {
- assert.shadowDom.equal(
- element,
+ assertEqualIgnoreWhitespaceAndNewlines(
+ element.innerHTML,
/* HTML */ `
- <gr-tooltip
- invisible
- id="tooltip"
- text="Press c to comment"
- ></gr-tooltip>
+ <!---->
+ <slot name="selectionActionBox" invisible="">
+ <gr-tooltip id="tooltip" text="Press c to comment"></gr-tooltip>
+ </slot>
`
);
});
@@ -111,10 +110,13 @@
test('renders visible', async () => {
await element.placeAbove(target);
await element.updateComplete;
- assert.shadowDom.equal(
- element,
+ assertEqualIgnoreWhitespaceAndNewlines(
+ element.innerHTML,
/* HTML */ `
- <gr-tooltip id="tooltip" text="Press c to comment"></gr-tooltip>
+ <!---->
+ <slot name="selectionActionBox">
+ <gr-tooltip id="tooltip" text="Press c to comment"></gr-tooltip>
+ </slot>
`
);
});
@@ -151,3 +153,21 @@
});
});
});
+
+function assertEqualIgnoreWhitespaceAndNewlines(
+ actual: string,
+ expected: string
+): void {
+ const normalize = (str: string): string =>
+ str
+ .replace(/\r/g, '')
+ .replace(/\n/g, '')
+ .replace(/\s+/g, ' ')
+ .replace(/\s+>/g, '>')
+ .trim();
+ if (normalize(actual) !== normalize(expected)) {
+ throw new Error(`Assertion failed:
+ Actual: "${normalize(actual)}"
+ Expected: "${normalize(expected)}"`);
+ }
+}
diff --git a/polygerrit-ui/app/styles/themes/app-theme.ts b/polygerrit-ui/app/styles/themes/app-theme.ts
index 2806936..97993c1 100644
--- a/polygerrit-ui/app/styles/themes/app-theme.ts
+++ b/polygerrit-ui/app/styles/themes/app-theme.ts
@@ -356,15 +356,15 @@
--tag-brown: var(--brown-50);
/* status colors */
- --status-merged: var(--green-700);
+ --status-merged: var(--gray-700);
--status-abandoned: var(--gray-700);
--status-wip: #795548;
--status-private: var(--purple-500);
--status-conflict: var(--red-600);
--status-revert: var(--gray-900);
--status-revert-created: #e64a19;
- --status-active: var(--blue-700);
- --status-ready: var(--pink-800);
+ --status-active: var(--yellow-700);
+ --status-ready: var(--green-700);
--status-custom: var(--purple-900);
/* file status colors */
diff --git a/polygerrit-ui/app/styles/themes/dark-theme.ts b/polygerrit-ui/app/styles/themes/dark-theme.ts
index 0387723..635d246 100644
--- a/polygerrit-ui/app/styles/themes/dark-theme.ts
+++ b/polygerrit-ui/app/styles/themes/dark-theme.ts
@@ -177,15 +177,15 @@
--tag-brown: var(--brown-tonal);
/* status colors */
- --status-merged: var(--green-400);
+ --status-merged: #a4a4a4;
--status-abandoned: var(--gray-300);
--status-wip: #bcaaa4;
--status-private: var(--purple-200);
--status-conflict: var(--red-300);
--status-revert: var(--gray-200);
--status-revert-created: #ff8a65;
- --status-active: var(--blue-400);
- --status-ready: var(--pink-500);
+ --status-active: #f4ce5d;
+ --status-ready: #55c374;
--status-custom: var(--purple-400);
/* file status colors */