Merge branch 'stable-7.6' into stable-7.7

* stable-7.6:
  junit.http: Extract AppServerBase to dedupe the EE8 AppServer overlay
  Bazel: Add EE8 servlet test targets
  Bazel: Add EE8 servlet bridge targets
  Bazel: Rename //lib:servlet-api to //lib:jakarta-servlet-api
  Bazel: format build files with buildifier
  PullCommandTest#testPullConflictDiff3: assert pull result

Change-Id: I6adcfbc8ac5d5fb6217fa70ed3c78fdb439faa9e
diff --git a/BUILD b/BUILD
index b8d8b9f..b9be9cb 100644
--- a/BUILD
+++ b/BUILD
@@ -10,8 +10,10 @@
         "//org.eclipse.jgit.archive:jgit-archive",
         "//org.eclipse.jgit.http.apache:http-apache",
         "//org.eclipse.jgit.http.server:jgit-servlet",
+        "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
         "//org.eclipse.jgit.lfs:jgit-lfs",
         "//org.eclipse.jgit.lfs.server:jgit-lfs-server",
+        "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8",
         "//org.eclipse.jgit.junit:junit",
         "//org.eclipse.jgit.ssh.apache:ssh-apache",
         "//org.eclipse.jgit.ssh.apache.agent:ssh-apache-agent",
diff --git a/MODULE.bazel b/MODULE.bazel
index 99528a3..58d86f5 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -4,6 +4,7 @@
 bazel_dep(name = "bazel_features", version = "1.39.0")
 bazel_dep(name = "rules_java", version = "8.16.1")
 bazel_dep(name = "rules_jvm_external", version = "6.10")
+bazel_dep(name = "rules_shell", version = "0.6.1")
 bazel_dep(name = "rbe_autoconfig")
 git_override(
     module_name = "rbe_autoconfig",
@@ -19,7 +20,7 @@
 
 git_repository(
     name = "com_googlesource_gerrit_bazlets",
-    commit = "f9c119e45d9a241bee720b7fbd6c7fdbc952da5f",
+    commit = "156bae8bb0d329d8886f681c723979cbdb39d37c",
     remote = "https://gerrit.googlesource.com/bazlets",
 )
 
@@ -51,6 +52,7 @@
         "commons-io:commons-io:2.22.0",
         "commons-logging:commons-logging:1.3.6",
         "jakarta.servlet:jakarta.servlet-api:6.1.0",
+        "javax.servlet:javax.servlet-api:4.0.1",
         "junit:junit:4.13.2",
         "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION,
         "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION,
@@ -76,6 +78,9 @@
         "org.eclipse.jetty:jetty-session:" + JETTY_VERSION,
         "org.eclipse.jetty:jetty-util-ajax:" + JETTY_VERSION,
         "org.eclipse.jetty:jetty-util:" + JETTY_VERSION,
+        "org.eclipse.jetty.ee8:jetty-ee8-nested:" + JETTY_VERSION,
+        "org.eclipse.jetty.ee8:jetty-ee8-security:" + JETTY_VERSION,
+        "org.eclipse.jetty.ee8:jetty-ee8-servlet:" + JETTY_VERSION,
         "org.eclipse.jetty.ee10:jetty-ee10-servlet:" + JETTY_VERSION,
         "org.hamcrest:hamcrest:3.0",
         "org.mockito:mockito-core:5.23.0",
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index 7faac96..535c4ce 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -213,7 +213,8 @@
     "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c",
     "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b",
     "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592",
-    "https://bcr.bazel.build/modules/rules_shell/0.4.1/source.json": "4757bd277fe1567763991c4425b483477bb82e35e777a56fd846eb5cceda324a",
+    "https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b",
+    "https://bcr.bazel.build/modules/rules_shell/0.6.1/source.json": "20ec05cd5e592055e214b2da8ccb283c7f2a421ea0dc2acbf1aa792e11c03d0c",
     "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca",
     "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046",
     "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186",
diff --git a/lib/BUILD b/lib/BUILD
index 20b85da..4ce0c1a 100644
--- a/lib/BUILD
+++ b/lib/BUILD
@@ -59,6 +59,7 @@
     visibility = [
         "//org.eclipse.jgit.lfs:__pkg__",
         "//org.eclipse.jgit.lfs.server:__pkg__",
+        "//org.eclipse.jgit.lfs.server.ee8:__pkg__",
     ],
     exports = ["@external_deps//:com_google_code_gson_gson"],
 )
@@ -68,6 +69,7 @@
     visibility = [
         "//org.eclipse.jgit.http.apache:__pkg__",
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
     ],
     exports = ["@external_deps//:org_apache_httpcomponents_httpclient"],
@@ -78,8 +80,11 @@
     visibility = [
         "//org.eclipse.jgit.http.apache:__pkg__",
         "//org.eclipse.jgit.http.test:__pkg__",
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
         "//org.eclipse.jgit.lfs.server:__pkg__",
+        "//org.eclipse.jgit.lfs.server.ee8:__pkg__",
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
     ],
     exports = ["@external_deps//:org_apache_httpcomponents_httpcore"],
@@ -177,6 +182,35 @@
 )
 
 java_library(
+    name = "jetty-ee8-nested",
+    testonly = 1,
+    visibility = ["//org.eclipse.jgit.junit.http.ee8:__pkg__"],
+    exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_nested"],
+)
+
+java_library(
+    name = "jetty-security-ee8",
+    testonly = 1,
+    visibility = [
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+    ],
+    exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_security"],
+)
+
+java_library(
+    name = "jetty-servlet-ee8",
+    testonly = 1,
+    visibility = [
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+    ],
+    exports = ["@external_deps//:org_eclipse_jetty_ee8_jetty_ee8_servlet"],
+)
+
+java_library(
     name = "jetty-util",
     # TODO: This should be testonly but org.eclipse.jgit.pgm depends on it.
     visibility = ["//visibility:public"],
@@ -264,10 +298,10 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = [
-        "@external_deps//:net_bytebuddy_byte_buddy_agent",
-        "@external_deps//:net_bytebuddy_byte_buddy",
-        "@external_deps//:org_hamcrest_hamcrest",
         "@external_deps//:junit_junit",
+        "@external_deps//:net_bytebuddy_byte_buddy",
+        "@external_deps//:net_bytebuddy_byte_buddy_agent",
+        "@external_deps//:org_hamcrest_hamcrest",
         "@external_deps//:org_mockito_mockito_core",
         "@external_deps//:org_objenesis_objenesis",
     ],
@@ -278,8 +312,8 @@
     testonly = 1,
     visibility = ["//visibility:public"],
     exports = [
-        "@external_deps//:net_bytebuddy_byte_buddy_agent",
         "@external_deps//:net_bytebuddy_byte_buddy",
+        "@external_deps//:net_bytebuddy_byte_buddy_agent",
         "@external_deps//:org_mockito_mockito_core",
         "@external_deps//:org_objenesis_objenesis",
     ],
@@ -295,12 +329,13 @@
 )
 
 java_library(
-    name = "servlet-api",
+    name = "jakarta-servlet-api",
     visibility = [
         "//org.eclipse.jgit.http.apache:__pkg__",
         "//org.eclipse.jgit.http.server:__pkg__",
         "//org.eclipse.jgit.http.test:__pkg__",
         "//org.eclipse.jgit.junit.http:__pkg__",
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
         "//org.eclipse.jgit.lfs.server:__pkg__",
         "//org.eclipse.jgit.lfs.server.test:__pkg__",
         "//org.eclipse.jgit.pgm:__pkg__",
@@ -309,6 +344,18 @@
 )
 
 java_library(
+    name = "javax-servlet-api",
+    visibility = [
+        "//org.eclipse.jgit.http.server.ee8:__pkg__",
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+        "//org.eclipse.jgit.lfs.server.ee8:__pkg__",
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+    ],
+    exports = ["@external_deps//:javax_servlet_javax_servlet_api"],
+)
+
+java_library(
     name = "slf4j-api",
     visibility = ["//visibility:public"],
     exports = ["@external_deps//:org_slf4j_slf4j_api"],
diff --git a/lib/jmh/BUILD b/lib/jmh/BUILD
index 2b15300..e6d3977 100644
--- a/lib/jmh/BUILD
+++ b/lib/jmh/BUILD
@@ -4,9 +4,9 @@
     name = "jmh",
     visibility = ["//visibility:public"],
     exports = [
-        "@external_deps//:org_openjdk_jmh_jmh_generator_annprocess",
-        "@external_deps//:org_openjdk_jmh_jmh_core",
         "@external_deps//:net_sf_jopt_simple_jopt_simple",
         "@external_deps//:org_apache_commons_commons_math3",
+        "@external_deps//:org_openjdk_jmh_jmh_core",
+        "@external_deps//:org_openjdk_jmh_jmh_generator_annprocess",
     ],
 )
diff --git a/org.eclipse.jgit.benchmarks/BUILD b/org.eclipse.jgit.benchmarks/BUILD
index 7c311e7..91ceb7f 100644
--- a/org.eclipse.jgit.benchmarks/BUILD
+++ b/org.eclipse.jgit.benchmarks/BUILD
@@ -6,8 +6,8 @@
 
 jmh_java_benchmarks(
     name = "benchmarks",
-    srcs = SRCS,
     testonly = 1,
+    srcs = SRCS,
     deps = [
         "//lib:javaewah",
         "//lib:junit",
diff --git a/org.eclipse.jgit.http.server.ee8/BUILD b/org.eclipse.jgit.http.server.ee8/BUILD
new file mode 100644
index 0000000..df39628
--- /dev/null
+++ b/org.eclipse.jgit.http.server.ee8/BUILD
@@ -0,0 +1,27 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+package(default_visibility = ["//visibility:public"])
+
+transform_srcjar(
+    name = "jgit-http-server-ee8-srcs",
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.http.server:srcs"],
+    src_prefix = "org.eclipse.jgit.http.server/src/",
+)
+
+filegroup(
+    name = "jgit-servlet-ee8-srcjar",
+    srcs = [":jgit-http-server-ee8-srcs"],
+)
+
+java_library(
+    name = "jgit-servlet-ee8",
+    srcs = [":jgit-http-server-ee8-srcs"],
+    resource_strip_prefix = "org.eclipse.jgit.http.server/resources",
+    resources = ["//org.eclipse.jgit.http.server:jgit-servlet-resources"],
+    deps = [
+        "//lib:javax-servlet-api",
+        "//org.eclipse.jgit:jgit",
+    ],
+)
diff --git a/org.eclipse.jgit.http.server/BUILD b/org.eclipse.jgit.http.server/BUILD
index a0dae48..f6b4a10 100644
--- a/org.eclipse.jgit.http.server/BUILD
+++ b/org.eclipse.jgit.http.server/BUILD
@@ -3,17 +3,26 @@
 package(default_visibility = ["//visibility:public"])
 
 filegroup(
+    name = "srcs",
+    srcs = glob(["src/**/*.java"]),
+    visibility = [
+        "//org.eclipse.jgit.http.server.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
     name = "jgit-servlet-resources",
     srcs = glob(["resources/**"]),
 )
 
 java_library(
     name = "jgit-servlet",
-    srcs = glob(["src/**/*.java"]),
+    srcs = [":srcs"],
     resource_strip_prefix = "org.eclipse.jgit.http.server/resources",
     resources = [":jgit-servlet-resources"],
     deps = [
-        "//lib:servlet-api",
+        "//lib:jakarta-servlet-api",
         # We want these deps to be provided_deps
         "//org.eclipse.jgit:jgit",
     ],
diff --git a/org.eclipse.jgit.http.test.ee8/BUILD b/org.eclipse.jgit.http.test.ee8/BUILD
new file mode 100644
index 0000000..a6a5506
--- /dev/null
+++ b/org.eclipse.jgit.http.test.ee8/BUILD
@@ -0,0 +1,84 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+transform_srcjar(
+    name = "helpers-srcs",
+    testonly = 1,
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.http.test:helper-srcs"],
+    src_prefix = "org.eclipse.jgit.http.test/src/",
+    visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+    name = "test-srcs",
+    testonly = 1,
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.http.test:test-srcs"],
+    src_prefix = "org.eclipse.jgit.http.test/tst/",
+    visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+    name = "server-unit-test-srcs",
+    testonly = 1,
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"],
+    src_prefix = "org.eclipse.jgit.http.test/tst/",
+)
+
+# Fast slice for the server utility tests; the default EE8 suite runs the full
+# HTTP test target, which already includes these classes.
+junit_tests(
+    name = "server_unit",
+    suite_srcs = ["//org.eclipse.jgit.http.test:http-server-unit-test-srcs"],
+    tags = ["http"],
+    srcs = [":server-unit-test-srcs"],
+    deps = [
+        "//lib:junit",
+        "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+        "//org.eclipse.jgit:jgit",
+        "//org.eclipse.jgit.junit:junit",
+    ],
+)
+
+junit_tests(
+    name = "http",
+    suite_srcs = ["//org.eclipse.jgit.http.test:test-srcs"],
+    tags = ["http"],
+    srcs = [":test-srcs"],
+    deps = [
+        ":helpers",
+        "//lib:commons-logging",
+        "//lib:httpcore",
+        "//lib:javax-servlet-api",
+        "//lib:jetty-http",
+        "//lib:jetty-io",
+        "//lib:jetty-security",
+        "//lib:jetty-security-ee8",
+        "//lib:jetty-server",
+        "//lib:jetty-servlet-ee8",
+        "//lib:jetty-util",
+        "//lib:junit",
+        "//lib:slf4j-api",
+        "//lib:slf4j-simple",
+        "//org.eclipse.jgit.http.apache:http-apache",
+        "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+        "//org.eclipse.jgit:jgit",
+        "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8",
+        "//org.eclipse.jgit.junit:junit",
+    ],
+)
+
+java_library(
+    name = "helpers",
+    testonly = 1,
+    srcs = [":helpers-srcs"],
+    deps = [
+        "//lib:javax-servlet-api",
+        "//lib:junit",
+        "//org.eclipse.jgit:jgit",
+        "//org.eclipse.jgit.junit:junit",
+    ],
+)
diff --git a/org.eclipse.jgit.http.test/BUILD b/org.eclipse.jgit.http.test/BUILD
index 732b4fa..cb6a738 100644
--- a/org.eclipse.jgit.http.test/BUILD
+++ b/org.eclipse.jgit.http.test/BUILD
@@ -4,14 +4,52 @@
 )
 load("@rules_java//java:defs.bzl", "java_library")
 
+HTTP_HELPER_SRCS = glob(["src/**/*.java"])
+
+HTTP_TEST_SRCS = glob(["tst/**/*.java"])
+
+HTTP_SERVER_UNIT_TEST_SRCS = [
+    "tst/org/eclipse/jgit/http/server/ClientVersionUtilTest.java",
+    "tst/org/eclipse/jgit/http/server/RootLocaleTest.java",
+    "tst/org/eclipse/jgit/http/server/ServletUtilsTest.java",
+]
+
+filegroup(
+    name = "helper-srcs",
+    testonly = 1,
+    srcs = HTTP_HELPER_SRCS,
+    visibility = [
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
+    name = "test-srcs",
+    testonly = 1,
+    srcs = HTTP_TEST_SRCS,
+    visibility = [
+        "//org.eclipse.jgit.http.test.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
+    name = "http-server-unit-test-srcs",
+    testonly = 1,
+    srcs = HTTP_SERVER_UNIT_TEST_SRCS,
+    visibility = ["//org.eclipse.jgit.http.test.ee8:__pkg__"],
+)
+
 junit_tests(
     name = "http",
-    srcs = glob(["tst/**/*.java"]),
+    srcs = HTTP_TEST_SRCS,
     tags = ["http"],
     deps = [
         ":helpers",
         "//lib:commons-logging",
         "//lib:httpcore",
+        "//lib:jakarta-servlet-api",
         "//lib:jetty-http",
         "//lib:jetty-io",
         "//lib:jetty-security",
@@ -19,7 +57,6 @@
         "//lib:jetty-servlet",
         "//lib:jetty-util",
         "//lib:junit",
-        "//lib:servlet-api",
         "//lib:slf4j-api",
         "//lib:slf4j-simple",
         "//org.eclipse.jgit.http.apache:http-apache",
@@ -33,10 +70,10 @@
 java_library(
     name = "helpers",
     testonly = 1,
-    srcs = glob(["src/**/*.java"]),
+    srcs = HTTP_HELPER_SRCS,
     deps = [
+        "//lib:jakarta-servlet-api",
         "//lib:junit",
-        "//lib:servlet-api",
         "//org.eclipse.jgit:jgit",
         "//org.eclipse.jgit.junit:junit",
     ],
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
index 3937627..2737a49 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
@@ -41,7 +41,7 @@
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.junit.TestRepository;
 import org.eclipse.jgit.junit.http.AccessEvent;
-import org.eclipse.jgit.junit.http.AppServer;
+import org.eclipse.jgit.junit.http.AppServerBase;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -266,12 +266,12 @@ public void testListRemote_Dumb_Auth() throws Exception {
 		Repository dst = createBareRepository();
 		try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
 			t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
-					AppServer.username, AppServer.password));
+					AppServerBase.username, AppServerBase.password));
 			t.openFetch().close();
 		}
 		try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
 			t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
-					AppServer.username, ""));
+					AppServerBase.username, ""));
 			try {
 				t.openFetch();
 				fail("connection opened even info/refs needs auth basic and we provide wrong password");
diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
index b0d17ad..46a48f7 100644
--- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
+++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
@@ -68,6 +68,7 @@
 import org.eclipse.jgit.junit.TestRng;
 import org.eclipse.jgit.junit.http.AccessEvent;
 import org.eclipse.jgit.junit.http.AppServer;
+import org.eclipse.jgit.junit.http.AppServerBase;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -111,7 +112,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase {
 	private Repository remoteRepository;
 
 	private CredentialsProvider testCredentials = new UsernamePasswordCredentialsProvider(
-			AppServer.username, AppServer.password);
+			AppServerBase.username, AppServerBase.password);
 
 	private URIish remoteURI;
 
@@ -998,7 +999,7 @@ public void testInitialClone_WithPreAuthentication() throws Exception {
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password);
+					AppServerBase.username, AppServerBase.password);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			assertTrue(dst.getObjectDatabase().has(A_txt));
 			assertEquals(B, dst.exactRef(master).getObjectId());
@@ -1018,7 +1019,7 @@ public void testInitialClone_WithPreAuthenticationCleared()
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password);
+					AppServerBase.username, AppServerBase.password);
 			((TransportHttp) t).setPreemptiveBasicAuthentication(null, null);
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
@@ -1043,7 +1044,7 @@ public void testInitialClone_PreAuthenticationTooLate() throws Exception {
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password);
+					AppServerBase.username, AppServerBase.password);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			assertTrue(dst.getObjectDatabase().has(A_txt));
 			assertEquals(B, dst.exactRef(master).getObjectId());
@@ -1053,7 +1054,7 @@ public void testInitialClone_PreAuthenticationTooLate() throws Exception {
 			assertFetchRequests(requests, 0);
 			assertThrows(IllegalStateException.class,
 					() -> ((TransportHttp) t).setPreemptiveBasicAuthentication(
-							AppServer.username, AppServer.password));
+							AppServerBase.username, AppServerBase.password));
 			assertThrows(IllegalStateException.class, () -> ((TransportHttp) t)
 					.setPreemptiveBasicAuthentication(null, null));
 		}
@@ -1066,7 +1067,7 @@ public void testInitialClone_WithWrongPreAuthenticationAndCredentialProvider()
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password + 'x');
+					AppServerBase.username, AppServerBase.password + 'x');
 			t.setCredentialsProvider(testCredentials);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			assertTrue(dst.getObjectDatabase().has(A_txt));
@@ -1090,7 +1091,7 @@ public void testInitialClone_WithWrongPreAuthentication() throws Exception {
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password + 'x');
+					AppServerBase.username, AppServerBase.password + 'x');
 			TransportException e = assertThrows(TransportException.class,
 					() -> t.fetch(NullProgressMonitor.INSTANCE,
 							mirror(master)));
@@ -1108,8 +1109,8 @@ public void testInitialClone_WithWrongPreAuthentication() throws Exception {
 
 	@Test
 	public void testInitialClone_WithUserInfo() throws Exception {
-		URIish withUserInfo = authURI.setUser(AppServer.username)
-				.setPass(AppServer.password);
+		URIish withUserInfo = authURI.setUser(AppServerBase.username)
+				.setPass(AppServerBase.password);
 		try (Repository dst = createBareRepository();
 				Transport t = Transport.open(dst, withUserInfo)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
@@ -1127,13 +1128,13 @@ public void testInitialClone_WithUserInfo() throws Exception {
 
 	@Test
 	public void testInitialClone_PreAuthOverridesUserInfo() throws Exception {
-		URIish withUserInfo = authURI.setUser(AppServer.username)
-				.setPass(AppServer.password + 'x');
+		URIish withUserInfo = authURI.setUser(AppServerBase.username)
+				.setPass(AppServerBase.password + 'x');
 		try (Repository dst = createBareRepository();
 				Transport t = Transport.open(dst, withUserInfo)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			((TransportHttp) t).setPreemptiveBasicAuthentication(
-					AppServer.username, AppServer.password);
+					AppServerBase.username, AppServerBase.password);
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			assertTrue(dst.getObjectDatabase().has(A_txt));
 			assertEquals(B, dst.exactRef(master).getObjectId());
@@ -1174,7 +1175,7 @@ public void testInitialClone_WithAuthenticationWrongCredentials()
 				Transport t = Transport.open(dst, authURI)) {
 			assertFalse(dst.getObjectDatabase().has(A_txt));
 			t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
-					AppServer.username, "wrongpassword"));
+					AppServerBase.username, "wrongpassword"));
 			t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
 			fail("Should not have succeeded -- wrong password");
 		} catch (TransportException e) {
diff --git a/org.eclipse.jgit.junit.http.ee8/BUILD b/org.eclipse.jgit.junit.http.ee8/BUILD
new file mode 100644
index 0000000..c7f6fb5
--- /dev/null
+++ b/org.eclipse.jgit.junit.http.ee8/BUILD
@@ -0,0 +1,43 @@
+load("@rules_java//java:defs.bzl", "java_library")
+
+package(default_visibility = ["//visibility:public"])
+
+java_library(
+    name = "junit-http-ee8",
+    testonly = 1,
+    srcs = [
+        "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs",
+        # AppServer diverges from the canonical Jakarta version and is copied
+        # from the servlet-4 branch as a hand-maintained EE8 overlay.
+        "src/org/eclipse/jgit/junit/http/AppServer.java",
+    ],
+    resources = glob(
+        ["resources/**"],
+        allow_empty = True,
+    ),
+    deps = [
+        "//lib:javax-servlet-api",
+        "//lib:jetty-ee8-nested",
+        "//lib:jetty-http",
+        "//lib:jetty-io",
+        "//lib:jetty-security",
+        "//lib:jetty-security-ee8",
+        "//lib:jetty-server",
+        "//lib:jetty-servlet-ee8",
+        "//lib:jetty-session",
+        "//lib:jetty-util",
+        "//lib:junit",
+        "//lib:slf4j-api",
+        "//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8",
+        "//org.eclipse.jgit:jgit",
+        "//org.eclipse.jgit.junit:junit",
+    ],
+)
+
+test_suite(
+    name = "tests",
+    tests = [
+        "//org.eclipse.jgit.http.test.ee8:http",
+        "//org.eclipse.jgit.lfs.server.test.ee8:lfs_server",
+    ],
+)
diff --git a/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java
new file mode 100644
index 0000000..3627d92
--- /dev/null
+++ b/org.eclipse.jgit.junit.http.ee8/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2010, 2017 Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.junit.http;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.jetty.ee8.nested.ServletConstraint;
+import org.eclipse.jetty.ee8.security.ConstraintMapping;
+import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee8.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.ee8.servlet.ServletContextHandler;
+import org.eclipse.jetty.security.AbstractLoginService;
+
+/**
+ * Tiny web application server for unit testing, wired for the EE8
+ * (javax.servlet / Jetty EE8) generation.
+ * <p>
+ * Only the Jetty security wiring is generation specific; everything else is
+ * inherited from the generated {@link AppServerBase}. This is the hand
+ * maintained EE8 overlay that the canonical {@code AppServer} cannot be
+ * rewritten into automatically, because the Jetty EE8 security API
+ * ({@code ServletConstraint} + {@code setSecurityHandler}) differs structurally
+ * from the EE10 one.
+ */
+public class AppServer extends AppServerBase {
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 */
+	public AppServer() {
+		super();
+	}
+
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
+	 * @param port
+	 *            the http port number; may be zero to allocate a port
+	 *            dynamically
+	 * @since 4.2
+	 */
+	public AppServer(int port) {
+		super(port);
+	}
+
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
+	 * @param port
+	 *            for http, may be zero to allocate a port dynamically
+	 * @param sslPort
+	 *            for https,may be zero to allocate a port dynamically. If
+	 *            negative, the server will be set up without https support.
+	 * @since 4.9
+	 */
+	public AppServer(int port, int sslPort) {
+		super(port, sslPort);
+	}
+
+	private ConstraintMapping createConstraintMapping() {
+		ConstraintMapping cm = new ConstraintMapping();
+		cm.setConstraint(new ServletConstraint());
+		cm.getConstraint().setAuthenticate(true);
+		cm.getConstraint().setDataConstraint(ServletConstraint.DC_NONE);
+		cm.getConstraint().setRoles(new String[] { authRole });
+		return cm;
+	}
+
+	@Override
+	protected void configureAuthentication(ServletContextHandler ctx,
+			String[] methods) {
+		AbstractLoginService users = new TestMappedLoginService(authRole);
+		List<ConstraintMapping> mappings = new ArrayList<>();
+		if (methods == null || methods.length == 0) {
+			ConstraintMapping cm = createConstraintMapping();
+			cm.setPathSpec("/*");
+			mappings.add(cm);
+		} else {
+			for (String method : methods) {
+				ConstraintMapping cm = createConstraintMapping();
+				cm.setMethod(method.toUpperCase(Locale.ROOT));
+				cm.setPathSpec("/*");
+				mappings.add(cm);
+			}
+		}
+
+		ConstraintSecurityHandler sec = new ConstraintSecurityHandler();
+		sec.setRealmName(realm);
+		sec.setAuthenticator(new BasicAuthenticator());
+		sec.setLoginService(users);
+		sec.setConstraintMappings(mappings.toArray(new ConstraintMapping[0]));
+		ctx.setSecurityHandler(sec);
+	}
+}
diff --git a/org.eclipse.jgit.junit.http/BUILD b/org.eclipse.jgit.junit.http/BUILD
index 66620ce..8ab98ac 100644
--- a/org.eclipse.jgit.junit.http/BUILD
+++ b/org.eclipse.jgit.junit.http/BUILD
@@ -1,14 +1,43 @@
 load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
 
 package(default_visibility = ["//visibility:public"])
 
+JUNIT_HTTP_SRCS = glob(["src/**/*.java"])
+
+JUNIT_HTTP_EE8_TRANSFORM_SRCS = glob(
+    ["src/**/*.java"],
+    exclude = ["src/org/eclipse/jgit/junit/http/AppServer.java"],
+)
+
+filegroup(
+    name = "srcs",
+    testonly = 1,
+    srcs = JUNIT_HTTP_SRCS,
+    visibility = [
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
+    name = "ee8-transform-srcs",
+    testonly = 1,
+    srcs = JUNIT_HTTP_EE8_TRANSFORM_SRCS,
+    visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
 java_library(
     name = "junit-http",
     testonly = 1,
-    srcs = glob(["src/**/*.java"]),
-    resources = glob(["resources/**"], allow_empty=True),
+    srcs = JUNIT_HTTP_SRCS,
+    resources = glob(
+        ["resources/**"],
+        allow_empty = True,
+    ),
     # TODO(davido): we want here provided deps
     deps = [
+        "//lib:jakarta-servlet-api",
         "//lib:jetty-http",
         "//lib:jetty-io",
         "//lib:jetty-security",
@@ -17,10 +46,20 @@
         "//lib:jetty-session",
         "//lib:jetty-util",
         "//lib:junit",
-        "//lib:servlet-api",
         "//lib:slf4j-api",
         "//org.eclipse.jgit.http.server:jgit-servlet",
         "//org.eclipse.jgit:jgit",
         "//org.eclipse.jgit.junit:junit",
     ],
 )
+
+transform_srcjar(
+    name = "junit-http-ee8-srcs",
+    direction = "to_javax",
+    sources = JUNIT_HTTP_EE8_TRANSFORM_SRCS,
+    src_prefix = "org.eclipse.jgit.junit.http/src/",
+    visibility = [
+        "//org.eclipse.jgit.junit.http.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
index 76e437b..3a4bce7 100644
--- a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServer.java
@@ -10,95 +10,30 @@
 
 package org.eclipse.jgit.junit.http;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.UnknownHostException;
-import java.nio.file.Files;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
 import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
 import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
 import org.eclipse.jetty.security.AbstractLoginService;
-import org.eclipse.jetty.security.Authenticator;
 import org.eclipse.jetty.security.Constraint;
-import org.eclipse.jetty.security.RolePrincipal;
-import org.eclipse.jetty.security.UserPrincipal;
 import org.eclipse.jetty.security.authentication.BasicAuthenticator;
-import org.eclipse.jetty.server.Connector;
-import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpConnectionFactory;
-import org.eclipse.jetty.server.SecureRequestCustomizer;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
-import org.eclipse.jetty.util.security.Password;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jgit.transport.URIish;
 
 /**
- * Tiny web application server for unit testing.
+ * Tiny web application server for unit testing, wired for the Jakarta servlet
+ * (Jetty EE10) generation.
  * <p>
- * Tests should start the server in their {@code setUp()} method and stop the
- * server in their {@code tearDown()} method. Only while started the server's
- * URL and/or port number can be obtained.
+ * Only the Jetty security wiring is generation specific; everything else lives
+ * in {@link AppServerBase}.
  */
-public class AppServer {
-	/** Realm name for the secure access areas. */
-	public static final String realm = "Secure Area";
-
-	/** Username for secured access areas. */
-	public static final String username = "agitter";
-
-	/** Password for {@link #username} in secured access areas. */
-	public static final String password = "letmein";
-
-	/** SSL keystore password; must have at least 6 characters. */
-	private static final String keyPassword = "mykeys";
-
-	/** Role for authentication. */
-	private static final String authRole = "can-access";
-
-	static {
-		// Install a logger that throws warning messages.
-		//
-		final String prop = "org.eclipse.jetty.util.log.class";
-		System.setProperty(prop, RecordingLogger.class.getName());
-	}
-
-	private final Server server;
-
-	private final HttpConfiguration config;
-
-	private final ServerConnector connector;
-
-	private final HttpConfiguration secureConfig;
-
-	private final ServerConnector secureConnector;
-
-	private final ContextHandlerCollection contexts;
-
-	private final TestRequestLog log;
-
-	private List<File> filesToDelete = new ArrayList<>();
-
+public class AppServer extends AppServerBase {
 	/**
 	 * Constructor for <code>AppServer</code>.
 	 */
 	public AppServer() {
-		this(0, -1);
+		super();
 	}
 
 	/**
@@ -110,7 +45,7 @@ public AppServer() {
 	 * @since 4.2
 	 */
 	public AppServer(int port) {
-		this(port, -1);
+		super(port);
 	}
 
 	/**
@@ -124,185 +59,7 @@ public AppServer(int port) {
 	 * @since 4.9
 	 */
 	public AppServer(int port, int sslPort) {
-		server = new Server();
-
-		config = new HttpConfiguration();
-		config.setSecureScheme("https");
-		config.setSecurePort(0);
-		config.setOutputBufferSize(32768);
-
-		connector = new ServerConnector(server,
-				new HttpConnectionFactory(config));
-		connector.setPort(port);
-		String ip;
-		String hostName;
-		try {
-			final InetAddress me = InetAddress.getByName("localhost");
-			ip = me.getHostAddress();
-			connector.setHost(ip);
-			hostName = InetAddress.getLocalHost().getCanonicalHostName();
-		} catch (UnknownHostException e) {
-			throw new RuntimeException("Cannot find localhost", e);
-		}
-
-		if (sslPort >= 0) {
-			SslContextFactory.Server sslContextFactory = createTestSslContextFactory(
-					hostName, ip);
-			secureConfig = new HttpConfiguration(config);
-			secureConfig.addCustomizer(new SecureRequestCustomizer());
-			HttpConnectionFactory http11 = new HttpConnectionFactory(
-					secureConfig);
-			SslConnectionFactory tls = new SslConnectionFactory(
-					sslContextFactory, http11.getProtocol());
-			secureConnector = new ServerConnector(server, tls, http11);
-			secureConnector.setPort(sslPort);
-			secureConnector.setHost(ip);
-		} else {
-			secureConfig = null;
-			secureConnector = null;
-		}
-
-		contexts = new ContextHandlerCollection();
-
-		log = new TestRequestLog();
-		log.setHandler(contexts);
-
-		if (secureConnector == null) {
-			server.setConnectors(new Connector[] { connector });
-		} else {
-			server.setConnectors(
-					new Connector[] { connector, secureConnector });
-		}
-		server.setHandler(log);
-	}
-
-	private SslContextFactory.Server createTestSslContextFactory(
-			String hostName, String ip) {
-		SslContextFactory.Server factory = new SslContextFactory.Server();
-
-		String dName = "CN=localhost,OU=JGit,O=Eclipse,ST=Ontario,L=Toronto,C=CA";
-
-		try {
-			File tmpDir = Files.createTempDirectory("jks").toFile();
-			tmpDir.deleteOnExit();
-			makePrivate(tmpDir);
-			File keyStore = new File(tmpDir, "keystore.jks");
-			File keytool = new File(
-					new File(new File(System.getProperty("java.home")), "bin"),
-					"keytool");
-			Runtime.getRuntime().exec(
-					new String[] {
-							keytool.getAbsolutePath(), //
-							"-keystore", keyStore.getAbsolutePath(), //
-							"-storepass", keyPassword,
-							"-alias", hostName, //
-							"-ext", "bc=ca:true", //
-							"-ext",
-							String.format(
-									"san=ip:%s,ip:127.0.0.1,ip:[::1],DNS:%s",
-									ip, hostName), //
-							"-genkeypair", //
-							"-keyalg", "RSA", //
-							"-keypass", keyPassword, //
-							"-dname", dName, //
-							"-validity", "2" //
-					}).waitFor();
-			keyStore.deleteOnExit();
-			makePrivate(keyStore);
-			filesToDelete.add(keyStore);
-			filesToDelete.add(tmpDir);
-			factory.setKeyStorePath(keyStore.getAbsolutePath());
-			factory.setKeyStorePassword(keyPassword);
-			factory.setKeyManagerPassword(keyPassword);
-			factory.setTrustStorePath(keyStore.getAbsolutePath());
-			factory.setTrustStorePassword(keyPassword);
-		} catch (InterruptedException | IOException e) {
-			throw new RuntimeException("Cannot create ssl key/certificate", e);
-		}
-		return factory;
-	}
-
-	private void makePrivate(File file) {
-		file.setReadable(false);
-		file.setWritable(false);
-		file.setExecutable(false);
-		file.setReadable(true, true);
-		file.setWritable(true, true);
-		if (file.isDirectory()) {
-			file.setExecutable(true, true);
-		}
-	}
-
-	/**
-	 * Create a new servlet context within the server.
-	 * <p>
-	 * This method should be invoked before the server is started, once for each
-	 * context the caller wants to register.
-	 *
-	 * @param path
-	 *            path of the context; use "/" for the root context if binding
-	 *            to the root is desired.
-	 * @return the context to add servlets into.
-	 * @since 7.0
-	 */
-	public ServletContextHandler addContext(String path) {
-		assertNotYetSetUp();
-		if ("".equals(path))
-			path = "/";
-
-		ServletContextHandler ctx = new ServletContextHandler();
-		ctx.setContextPath(path);
-		contexts.addHandler(ctx);
-
-		return ctx;
-	}
-
-	/**
-	 * Configure basic authentication.
-	 *
-	 * @param ctx
-	 *            servlet context handler
-	 * @param methods
-	 *            the methods
-	 * @return servlet context handler
-	 * @since 7.0
-	 */
-	public ServletContextHandler authBasic(ServletContextHandler ctx,
-			String... methods) {
-		assertNotYetSetUp();
-		auth(ctx, new BasicAuthenticator(), methods);
-		return ctx;
-	}
-
-	static class TestMappedLoginService extends AbstractLoginService {
-		private RolePrincipal role;
-
-		protected final Map<String, UserPrincipal> users = new ConcurrentHashMap<>();
-
-		TestMappedLoginService(String role) {
-			this.role = new RolePrincipal(role);
-		}
-
-		@Override
-		protected void doStart() throws Exception {
-			UserPrincipal p = new UserPrincipal(username,
-					new Password(password));
-			users.put(username, p);
-			super.doStart();
-		}
-
-		@Override
-		protected UserPrincipal loadUserInfo(String user) {
-			return users.get(user);
-		}
-
-		@Override
-		protected List<RolePrincipal> loadRoleInfo(UserPrincipal user) {
-			if (users.get(user.getName()) == null) {
-				return null;
-			}
-			return Collections.singletonList(role);
-		}
+		super(port, sslPort);
 	}
 
 	private ConstraintMapping createConstraintMapping() {
@@ -315,8 +72,9 @@ private ConstraintMapping createConstraintMapping() {
 		return cm;
 	}
 
-	private void auth(ServletContextHandler ctx, Authenticator authType,
-			String... methods) {
+	@Override
+	protected void configureAuthentication(ServletContextHandler ctx,
+			String[] methods) {
 		AbstractLoginService users = new TestMappedLoginService(authRole);
 		List<ConstraintMapping> mappings = new ArrayList<>();
 		if (methods == null || methods.length == 0) {
@@ -331,133 +89,12 @@ private void auth(ServletContextHandler ctx, Authenticator authType,
 
 		ConstraintSecurityHandler sec = new ConstraintSecurityHandler();
 		sec.setRealmName(realm);
-		sec.setAuthenticator(authType);
+		sec.setAuthenticator(new BasicAuthenticator());
 		sec.setLoginService(users);
-		sec.setConstraintMappings(
-				mappings.toArray(new ConstraintMapping[0]));
+		sec.setConstraintMappings(mappings.toArray(new ConstraintMapping[0]));
 		sec.setHandler(ctx);
 
 		contexts.removeHandler(ctx);
 		contexts.addHandler(sec);
 	}
-
-	/**
-	 * Start the server on a random local port.
-	 *
-	 * @throws Exception
-	 *             the server cannot be started, testing is not possible.
-	 */
-	public void setUp() throws Exception {
-		RecordingLogger.clear();
-		log.clear();
-		server.start();
-		config.setSecurePort(getSecurePort());
-		if (secureConfig != null) {
-			secureConfig.setSecurePort(getSecurePort());
-		}
-	}
-
-	/**
-	 * Shutdown the server.
-	 *
-	 * @throws Exception
-	 *             the server refuses to halt, or wasn't running.
-	 */
-	public void tearDown() throws Exception {
-		RecordingLogger.clear();
-		log.clear();
-		server.stop();
-		for (File f : filesToDelete) {
-			f.delete();
-		}
-		filesToDelete.clear();
-	}
-
-	/**
-	 * Get the URI to reference this server.
-	 * <p>
-	 * The returned URI includes the proper host name and port number, but does
-	 * not contain a path.
-	 *
-	 * @return URI to reference this server's root context.
-	 */
-	public URI getURI() {
-		assertAlreadySetUp();
-		String host = connector.getHost();
-		if (host.contains(":") && !host.startsWith("["))
-			host = "[" + host + "]";
-		final String uri = "http://" + host + ":" + getPort();
-		try {
-			return new URI(uri);
-		} catch (URISyntaxException e) {
-			throw new RuntimeException("Unexpected URI error on " + uri, e);
-		}
-	}
-
-	/**
-	 * Get port.
-	 *
-	 * @return the local port number the server is listening on.
-	 */
-	public int getPort() {
-		assertAlreadySetUp();
-		return connector.getLocalPort();
-	}
-
-	/**
-	 * Get secure port.
-	 *
-	 * @return the HTTPS port or -1 if not configured.
-	 */
-	public int getSecurePort() {
-		assertAlreadySetUp();
-		return secureConnector != null ? secureConnector.getLocalPort() : -1;
-	}
-
-	/**
-	 * Get requests.
-	 *
-	 * @return all requests since the server was started.
-	 */
-	public List<AccessEvent> getRequests() {
-		return new ArrayList<>(log.getEvents());
-	}
-
-	/**
-	 * Get requests.
-	 *
-	 * @param base
-	 *            base URI used to access the server.
-	 * @param path
-	 *            the path to locate requests for, relative to {@code base}.
-	 * @return all requests which match the given path.
-	 */
-	public List<AccessEvent> getRequests(URIish base, String path) {
-		return getRequests(HttpTestCase.join(base, path));
-	}
-
-	/**
-	 * Get requests.
-	 *
-	 * @param path
-	 *            the path to locate requests for.
-	 * @return all requests which match the given path.
-	 */
-	public List<AccessEvent> getRequests(String path) {
-		ArrayList<AccessEvent> r = new ArrayList<>();
-		for (AccessEvent event : log.getEvents()) {
-			if (event.getPath().equals(path)) {
-				r.add(event);
-			}
-		}
-		return r;
-	}
-
-	private void assertNotYetSetUp() {
-		assertFalse("server is not running", server.isRunning());
-	}
-
-	private void assertAlreadySetUp() {
-		assertTrue("server is running", server.isRunning());
-	}
 }
diff --git a/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java
new file mode 100644
index 0000000..bc2baad
--- /dev/null
+++ b/org.eclipse.jgit.junit.http/src/org/eclipse/jgit/junit/http/AppServerBase.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2010, 2017 Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.junit.http;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.UnknownHostException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.eclipse.jetty.security.AbstractLoginService;
+import org.eclipse.jetty.security.RolePrincipal;
+import org.eclipse.jetty.security.UserPrincipal;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.HttpConfiguration;
+import org.eclipse.jetty.server.HttpConnectionFactory;
+import org.eclipse.jetty.server.SecureRequestCustomizer;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.util.security.Password;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jgit.transport.URIish;
+
+/**
+ * Tiny web application server for unit testing.
+ * <p>
+ * Tests should start the server in their {@code setUp()} method and stop the
+ * server in their {@code tearDown()} method. Only while started the server's
+ * URL and/or port number can be obtained.
+ * <p>
+ * The Jetty security API for declaring authentication constraints differs
+ * between EE generations. That part is therefore isolated in the abstract
+ * {@link #configureAuthentication(ServletContextHandler, String[])} seam, which
+ * the concrete {@code AppServer} provides for its servlet generation.
+ */
+public abstract class AppServerBase {
+	/** Realm name for the secure access areas. */
+	public static final String realm = "Secure Area";
+
+	/** Username for secured access areas. */
+	public static final String username = "agitter";
+
+	/** Password for {@link #username} in secured access areas. */
+	public static final String password = "letmein";
+
+	/** SSL keystore password; must have at least 6 characters. */
+	private static final String keyPassword = "mykeys";
+
+	/** Role for authentication. */
+	protected static final String authRole = "can-access";
+
+	static {
+		// Install a logger that throws warning messages.
+		//
+		final String prop = "org.eclipse.jetty.util.log.class";
+		System.setProperty(prop, RecordingLogger.class.getName());
+	}
+
+	private final Server server;
+
+	private final HttpConfiguration config;
+
+	private final ServerConnector connector;
+
+	private final HttpConfiguration secureConfig;
+
+	private final ServerConnector secureConnector;
+
+	/** Collection the servlet contexts are registered in. */
+	protected final ContextHandlerCollection contexts;
+
+	private final TestRequestLog log;
+
+	private List<File> filesToDelete = new ArrayList<>();
+
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 */
+	protected AppServerBase() {
+		this(0, -1);
+	}
+
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
+	 * @param port
+	 *            the http port number; may be zero to allocate a port
+	 *            dynamically
+	 */
+	protected AppServerBase(int port) {
+		this(port, -1);
+	}
+
+	/**
+	 * Constructor for <code>AppServer</code>.
+	 *
+	 * @param port
+	 *            for http, may be zero to allocate a port dynamically
+	 * @param sslPort
+	 *            for https,may be zero to allocate a port dynamically. If
+	 *            negative, the server will be set up without https support.
+	 */
+	protected AppServerBase(int port, int sslPort) {
+		server = new Server();
+
+		config = new HttpConfiguration();
+		config.setSecureScheme("https");
+		config.setSecurePort(0);
+		config.setOutputBufferSize(32768);
+
+		connector = new ServerConnector(server,
+				new HttpConnectionFactory(config));
+		connector.setPort(port);
+		String ip;
+		String hostName;
+		try {
+			final InetAddress me = InetAddress.getByName("localhost");
+			ip = me.getHostAddress();
+			connector.setHost(ip);
+			hostName = InetAddress.getLocalHost().getCanonicalHostName();
+		} catch (UnknownHostException e) {
+			throw new RuntimeException("Cannot find localhost", e);
+		}
+
+		if (sslPort >= 0) {
+			SslContextFactory.Server sslContextFactory = createTestSslContextFactory(
+					hostName, ip);
+			secureConfig = new HttpConfiguration(config);
+			secureConfig.addCustomizer(new SecureRequestCustomizer());
+			HttpConnectionFactory http11 = new HttpConnectionFactory(
+					secureConfig);
+			SslConnectionFactory tls = new SslConnectionFactory(
+					sslContextFactory, http11.getProtocol());
+			secureConnector = new ServerConnector(server, tls, http11);
+			secureConnector.setPort(sslPort);
+			secureConnector.setHost(ip);
+		} else {
+			secureConfig = null;
+			secureConnector = null;
+		}
+
+		contexts = new ContextHandlerCollection();
+
+		log = new TestRequestLog();
+		log.setHandler(contexts);
+
+		if (secureConnector == null) {
+			server.setConnectors(new Connector[] { connector });
+		} else {
+			server.setConnectors(
+					new Connector[] { connector, secureConnector });
+		}
+		server.setHandler(log);
+	}
+
+	private SslContextFactory.Server createTestSslContextFactory(
+			String hostName, String ip) {
+		SslContextFactory.Server factory = new SslContextFactory.Server();
+
+		String dName = "CN=localhost,OU=JGit,O=Eclipse,ST=Ontario,L=Toronto,C=CA";
+
+		try {
+			File tmpDir = Files.createTempDirectory("jks").toFile();
+			tmpDir.deleteOnExit();
+			makePrivate(tmpDir);
+			File keyStore = new File(tmpDir, "keystore.jks");
+			File keytool = new File(
+					new File(new File(System.getProperty("java.home")), "bin"),
+					"keytool");
+			Runtime.getRuntime().exec(
+					new String[] {
+							keytool.getAbsolutePath(), //
+							"-keystore", keyStore.getAbsolutePath(), //
+							"-storepass", keyPassword,
+							"-alias", hostName, //
+							"-ext", "bc=ca:true", //
+							"-ext",
+							String.format(
+									"san=ip:%s,ip:127.0.0.1,ip:[::1],DNS:%s",
+									ip, hostName), //
+							"-genkeypair", //
+							"-keyalg", "RSA", //
+							"-keypass", keyPassword, //
+							"-dname", dName, //
+							"-validity", "2" //
+					}).waitFor();
+			keyStore.deleteOnExit();
+			makePrivate(keyStore);
+			filesToDelete.add(keyStore);
+			filesToDelete.add(tmpDir);
+			factory.setKeyStorePath(keyStore.getAbsolutePath());
+			factory.setKeyStorePassword(keyPassword);
+			factory.setKeyManagerPassword(keyPassword);
+			factory.setTrustStorePath(keyStore.getAbsolutePath());
+			factory.setTrustStorePassword(keyPassword);
+		} catch (InterruptedException | IOException e) {
+			throw new RuntimeException("Cannot create ssl key/certificate", e);
+		}
+		return factory;
+	}
+
+	private void makePrivate(File file) {
+		file.setReadable(false);
+		file.setWritable(false);
+		file.setExecutable(false);
+		file.setReadable(true, true);
+		file.setWritable(true, true);
+		if (file.isDirectory()) {
+			file.setExecutable(true, true);
+		}
+	}
+
+	/**
+	 * Create a new servlet context within the server.
+	 * <p>
+	 * This method should be invoked before the server is started, once for each
+	 * context the caller wants to register.
+	 *
+	 * @param path
+	 *            path of the context; use "/" for the root context if binding
+	 *            to the root is desired.
+	 * @return the context to add servlets into.
+	 * @since 7.0
+	 */
+	public ServletContextHandler addContext(String path) {
+		assertNotYetSetUp();
+		if ("".equals(path))
+			path = "/";
+
+		ServletContextHandler ctx = new ServletContextHandler();
+		ctx.setContextPath(path);
+		contexts.addHandler(ctx);
+
+		return ctx;
+	}
+
+	/**
+	 * Configure basic authentication.
+	 *
+	 * @param ctx
+	 *            servlet context handler
+	 * @param methods
+	 *            the methods
+	 * @return servlet context handler
+	 * @since 7.0
+	 */
+	public ServletContextHandler authBasic(ServletContextHandler ctx,
+			String... methods) {
+		assertNotYetSetUp();
+		configureAuthentication(ctx, methods);
+		return ctx;
+	}
+
+	/**
+	 * Install basic-authentication constraints on the given context.
+	 * <p>
+	 * The Jetty security API used to build the constraints and attach the
+	 * security handler differs between servlet generations, so each concrete
+	 * {@code AppServer} implements this seam for its Jetty flavor.
+	 *
+	 * @param ctx
+	 *            servlet context handler to secure
+	 * @param methods
+	 *            HTTP methods to constrain; empty constrains all methods
+	 */
+	protected abstract void configureAuthentication(ServletContextHandler ctx,
+			String[] methods);
+
+	/** Login service mapping the single test user and role. */
+	protected static class TestMappedLoginService extends AbstractLoginService {
+		private RolePrincipal role;
+
+		protected final Map<String, UserPrincipal> users = new ConcurrentHashMap<>();
+
+		TestMappedLoginService(String role) {
+			this.role = new RolePrincipal(role);
+		}
+
+		@Override
+		protected void doStart() throws Exception {
+			UserPrincipal p = new UserPrincipal(username,
+					new Password(password));
+			users.put(username, p);
+			super.doStart();
+		}
+
+		@Override
+		protected UserPrincipal loadUserInfo(String user) {
+			return users.get(user);
+		}
+
+		@Override
+		protected List<RolePrincipal> loadRoleInfo(UserPrincipal user) {
+			if (users.get(user.getName()) == null) {
+				return null;
+			}
+			return Collections.singletonList(role);
+		}
+	}
+
+	/**
+	 * Start the server on a random local port.
+	 *
+	 * @throws Exception
+	 *             the server cannot be started, testing is not possible.
+	 */
+	public void setUp() throws Exception {
+		RecordingLogger.clear();
+		log.clear();
+		server.start();
+		config.setSecurePort(getSecurePort());
+		if (secureConfig != null) {
+			secureConfig.setSecurePort(getSecurePort());
+		}
+	}
+
+	/**
+	 * Shutdown the server.
+	 *
+	 * @throws Exception
+	 *             the server refuses to halt, or wasn't running.
+	 */
+	public void tearDown() throws Exception {
+		RecordingLogger.clear();
+		log.clear();
+		server.stop();
+		for (File f : filesToDelete) {
+			f.delete();
+		}
+		filesToDelete.clear();
+	}
+
+	/**
+	 * Get the URI to reference this server.
+	 * <p>
+	 * The returned URI includes the proper host name and port number, but does
+	 * not contain a path.
+	 *
+	 * @return URI to reference this server's root context.
+	 */
+	public URI getURI() {
+		assertAlreadySetUp();
+		String host = connector.getHost();
+		if (host.contains(":") && !host.startsWith("["))
+			host = "[" + host + "]";
+		final String uri = "http://" + host + ":" + getPort();
+		try {
+			return new URI(uri);
+		} catch (URISyntaxException e) {
+			throw new RuntimeException("Unexpected URI error on " + uri, e);
+		}
+	}
+
+	/**
+	 * Get port.
+	 *
+	 * @return the local port number the server is listening on.
+	 */
+	public int getPort() {
+		assertAlreadySetUp();
+		return connector.getLocalPort();
+	}
+
+	/**
+	 * Get secure port.
+	 *
+	 * @return the HTTPS port or -1 if not configured.
+	 */
+	public int getSecurePort() {
+		assertAlreadySetUp();
+		return secureConnector != null ? secureConnector.getLocalPort() : -1;
+	}
+
+	/**
+	 * Get requests.
+	 *
+	 * @return all requests since the server was started.
+	 */
+	public List<AccessEvent> getRequests() {
+		return new ArrayList<>(log.getEvents());
+	}
+
+	/**
+	 * Get requests.
+	 *
+	 * @param base
+	 *            base URI used to access the server.
+	 * @param path
+	 *            the path to locate requests for, relative to {@code base}.
+	 * @return all requests which match the given path.
+	 */
+	public List<AccessEvent> getRequests(URIish base, String path) {
+		return getRequests(HttpTestCase.join(base, path));
+	}
+
+	/**
+	 * Get requests.
+	 *
+	 * @param path
+	 *            the path to locate requests for.
+	 * @return all requests which match the given path.
+	 */
+	public List<AccessEvent> getRequests(String path) {
+		ArrayList<AccessEvent> r = new ArrayList<>();
+		for (AccessEvent event : log.getEvents()) {
+			if (event.getPath().equals(path)) {
+				r.add(event);
+			}
+		}
+		return r;
+	}
+
+	private void assertNotYetSetUp() {
+		assertFalse("server is not running", server.isRunning());
+	}
+
+	private void assertAlreadySetUp() {
+		assertTrue("server is running", server.isRunning());
+	}
+}
diff --git a/org.eclipse.jgit.junit/BUILD b/org.eclipse.jgit.junit/BUILD
index f4a7165..8879cd9 100644
--- a/org.eclipse.jgit.junit/BUILD
+++ b/org.eclipse.jgit.junit/BUILD
@@ -7,7 +7,10 @@
     testonly = 1,
     srcs = glob(["src/**/*.java"]),
     resource_strip_prefix = "org.eclipse.jgit.junit/resources",
-    resources = glob(["resources/**"], allow_empty=True),
+    resources = glob(
+        ["resources/**"],
+        allow_empty = True,
+    ),
     deps = [
         "//lib:junit",
         # We want these deps to be provided_deps
diff --git a/org.eclipse.jgit.lfs.server.ee8/BUILD b/org.eclipse.jgit.lfs.server.ee8/BUILD
new file mode 100644
index 0000000..b07dae2
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server.ee8/BUILD
@@ -0,0 +1,32 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+package(default_visibility = ["//visibility:public"])
+
+transform_srcjar(
+    name = "jgit-lfs-server-ee8-srcs",
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.lfs.server:srcs"],
+    src_prefix = "org.eclipse.jgit.lfs.server/src/",
+)
+
+filegroup(
+    name = "jgit-lfs-server-ee8-srcjar",
+    srcs = [":jgit-lfs-server-ee8-srcs"],
+)
+
+java_library(
+    name = "jgit-lfs-server-ee8",
+    srcs = [":jgit-lfs-server-ee8-srcs"],
+    resource_strip_prefix = "org.eclipse.jgit.lfs.server/resources",
+    resources = ["//org.eclipse.jgit.lfs.server:jgit-lfs-server-resources"],
+    deps = [
+        "//lib:gson",
+        "//lib:httpcore",
+        "//lib:javax-servlet-api",
+        "//lib:slf4j-api",
+        "//org.eclipse.jgit.http.apache:http-apache",
+        "//org.eclipse.jgit:jgit",
+        "//org.eclipse.jgit.lfs:jgit-lfs",
+    ],
+)
diff --git a/org.eclipse.jgit.lfs.server.test.ee8/BUILD b/org.eclipse.jgit.lfs.server.test.ee8/BUILD
new file mode 100644
index 0000000..bb93b79
--- /dev/null
+++ b/org.eclipse.jgit.lfs.server.test.ee8/BUILD
@@ -0,0 +1,65 @@
+load("@rules_java//java:defs.bzl", "java_library")
+load("@com_googlesource_gerrit_bazlets//tools:junit.bzl", "junit_tests")
+load("@com_googlesource_gerrit_bazlets//tools:servlet_transform.bzl", "transform_srcjar")
+
+transform_srcjar(
+    name = "test-srcs",
+    testonly = 1,
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.lfs.server.test:test-srcs"],
+    src_prefix = "org.eclipse.jgit.lfs.server.test/tst/",
+    visibility = ["//tools/jgit-ee8:__pkg__"],
+)
+
+transform_srcjar(
+    name = "base-test-srcs",
+    testonly = 1,
+    direction = "to_javax",
+    sources = ["//org.eclipse.jgit.lfs.server.test:base-test-srcs"],
+    src_prefix = "org.eclipse.jgit.lfs.server.test/tst/",
+)
+
+# Keep the helper/base class separate: the canonical LfsServerTest is compiled
+# into the helper jar, while the remaining tests are executed from the EE8
+# suite target.
+DEPS = [
+    "//org.eclipse.jgit.lfs.test:helpers",
+    "//org.eclipse.jgit:jgit",
+    "//org.eclipse.jgit.junit:junit",
+    "//org.eclipse.jgit.junit.http.ee8:junit-http-ee8",
+    "//org.eclipse.jgit.lfs:jgit-lfs",
+    "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8",
+    "//lib:commons-logging",
+    "//lib:httpcore",
+    "//lib:httpclient",
+    "//lib:junit",
+    "//lib:jetty-http",
+    "//lib:jetty-io",
+    "//lib:jetty-server",
+    "//lib:jetty-servlet-ee8",
+    "//lib:jetty-security",
+    "//lib:jetty-security-ee8",
+    "//lib:jetty-util",
+    "//lib:javax-servlet-api",
+]
+
+junit_tests(
+    name = "lfs_server",
+    jvm_flags = [
+        "-Xmx512m",
+        "-Dfile.encoding=UTF-8",
+    ],
+    suite_srcs = ["//org.eclipse.jgit.lfs.server.test:nonbase-test-srcs"],
+    tags = ["lfs-server"],
+    srcs = [":test-srcs"],
+    deps = DEPS + [
+        ":helpers",
+    ],
+)
+
+java_library(
+    name = "helpers",
+    testonly = 1,
+    srcs = [":base-test-srcs"],
+    deps = DEPS,
+)
diff --git a/org.eclipse.jgit.lfs.server.test/BUILD b/org.eclipse.jgit.lfs.server.test/BUILD
index 76a0870..4b69804 100644
--- a/org.eclipse.jgit.lfs.server.test/BUILD
+++ b/org.eclipse.jgit.lfs.server.test/BUILD
@@ -6,6 +6,35 @@
 
 TEST_BASE = ["tst/org/eclipse/jgit/lfs/server/fs/LfsServerTest.java"]
 
+TEST_SRCS = glob(["tst/**/*.java"])
+
+filegroup(
+    name = "test-srcs",
+    testonly = 1,
+    srcs = TEST_SRCS,
+    visibility = [
+        "//org.eclipse.jgit.lfs.server.test.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
+    name = "base-test-srcs",
+    testonly = 1,
+    srcs = TEST_BASE,
+    visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"],
+)
+
+filegroup(
+    name = "nonbase-test-srcs",
+    testonly = 1,
+    srcs = glob(
+        ["tst/**/*.java"],
+        exclude = TEST_BASE,
+    ),
+    visibility = ["//org.eclipse.jgit.lfs.server.test.ee8:__pkg__"],
+)
+
 DEPS = [
     "//org.eclipse.jgit.lfs.test:helpers",
     "//org.eclipse.jgit:jgit",
@@ -23,7 +52,7 @@
     "//lib:jetty-servlet",
     "//lib:jetty-security",
     "//lib:jetty-util",
-    "//lib:servlet-api",
+    "//lib:jakarta-servlet-api",
 ]
 
 junit_tests(
diff --git a/org.eclipse.jgit.lfs.server/BUILD b/org.eclipse.jgit.lfs.server/BUILD
index cd1831b..d6b08a6 100644
--- a/org.eclipse.jgit.lfs.server/BUILD
+++ b/org.eclipse.jgit.lfs.server/BUILD
@@ -2,15 +2,29 @@
 
 package(default_visibility = ["//visibility:public"])
 
+filegroup(
+    name = "srcs",
+    srcs = glob(["src/**/*.java"]),
+    visibility = [
+        "//org.eclipse.jgit.lfs.server.ee8:__pkg__",
+        "//tools/jgit-ee8:__pkg__",
+    ],
+)
+
+filegroup(
+    name = "jgit-lfs-server-resources",
+    srcs = glob(["resources/**"]),
+)
+
 java_library(
     name = "jgit-lfs-server",
-    srcs = glob(["src/**/*.java"]),
+    srcs = [":srcs"],
     resource_strip_prefix = "org.eclipse.jgit.lfs.server/resources",
-    resources = glob(["resources/**"]),
+    resources = [":jgit-lfs-server-resources"],
     deps = [
         "//lib:gson",
         "//lib:httpcore",
-        "//lib:servlet-api",
+        "//lib:jakarta-servlet-api",
         "//lib:slf4j-api",
         "//org.eclipse.jgit.http.apache:http-apache",
         "//org.eclipse.jgit:jgit",
diff --git a/org.eclipse.jgit.pgm.test/BUILD b/org.eclipse.jgit.pgm.test/BUILD
index b8ffa69..fdd87d3 100644
--- a/org.eclipse.jgit.pgm.test/BUILD
+++ b/org.eclipse.jgit.pgm.test/BUILD
@@ -15,8 +15,8 @@
     deps = [
         ":helpers",
         "//lib:args4j",
-        "//lib:commons-io",
         "//lib:commons-compress",
+        "//lib:commons-io",
         "//lib:javaewah",
         "//lib:junit",
         "//lib:slf4j-api",
diff --git a/org.eclipse.jgit.pgm/BUILD b/org.eclipse.jgit.pgm/BUILD
index a267b15..596aed2 100644
--- a/org.eclipse.jgit.pgm/BUILD
+++ b/org.eclipse.jgit.pgm/BUILD
@@ -16,13 +16,13 @@
         "//lib:commons-logging",
         "//lib:httpclient",
         "//lib:httpcore",
+        "//lib:jakarta-servlet-api",
         "//lib:jetty-http",
         "//lib:jetty-io",
         "//lib:jetty-security",
         "//lib:jetty-server",
         "//lib:jetty-servlet",
         "//lib:jetty-util",
-        "//lib:servlet-api",
         "//org.eclipse.jgit.archive:jgit-archive",
         "//org.eclipse.jgit.http.apache:http-apache",
         "//org.eclipse.jgit:jgit",
diff --git a/org.eclipse.jgit.test/BUILD b/org.eclipse.jgit.test/BUILD
index 7755df0..7dab36d 100644
--- a/org.eclipse.jgit.test/BUILD
+++ b/org.eclipse.jgit.test/BUILD
@@ -53,10 +53,11 @@
     exclude = HELPERS + DATA + EXCLUDED,
 ))
 
-
-tests(tests = glob(["exttst/**/*.java"]),
+tests(
+    extra_tags = ["ext"],
     srcprefix = "exttst/",
-    extra_tags = ["ext"])
+    tests = glob(["exttst/**/*.java"]),
+)
 
 # Non abstract base classes used for tests by other test classes
 BASE = [
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
index 8d6e7bc..2dc77cf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -188,7 +188,10 @@ public void testPullConflictDiff3() throws Exception {
 		target.getRepository().getConfig().setEnum(CONFIG_MERGE_SECTION, null,
 				CONFIG_KEY_CONFLICTSTYLE, ConflictStyle.DIFF3);
 
-		target.pull().call();
+		res = target.pull().call();
+		assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty());
+		assertTrue(res.getMergeResult().getMergeStatus()
+				.equals(MergeStatus.CONFLICTING));
 
 		String sourceChangeString = "Source change\n>>>>>>> branch 'master' of "
 				+ target.getRepository().getConfig().getString("remote",
diff --git a/org.eclipse.jgit/BUILD b/org.eclipse.jgit/BUILD
index 1e9b770..5d4bce4 100644
--- a/org.eclipse.jgit/BUILD
+++ b/org.eclipse.jgit/BUILD
@@ -16,6 +16,12 @@
 java_library(
     name = "jgit_non_stamped",
     srcs = SRCS,
+    javacopts = [
+        "-Xep:ReferenceEquality:OFF",
+        "-Xep:StringEquality:OFF",
+        "-Xep:TypeParameterUnusedInFormals:OFF",
+        "-Xep:DefaultCharset:OFF",
+    ],
     resource_strip_prefix = "org.eclipse.jgit/resources",
     resources = RESOURCES,
     deps = [
@@ -24,12 +30,6 @@
         "//lib:javaewah",
         "//lib:slf4j-api",
     ],
-    javacopts = [
-        "-Xep:ReferenceEquality:OFF",
-        "-Xep:StringEquality:OFF",
-        "-Xep:TypeParameterUnusedInFormals:OFF",
-        "-Xep:DefaultCharset:OFF",
-    ]
 )
 
 genrule(
diff --git a/tools/BUILD b/tools/BUILD
index 379a9bd..4238054 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -35,398 +35,399 @@
 # https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl
 # However, feel free to add any additional errors. Thus far they have all been pretty useful.
 errorprone_checks = [
-        "-XepDisableWarningsInGeneratedCode",
-        # The XepDisableWarningsInGeneratedCode disables only warnings, but
-        # not errors. We should manually exclude all files generated by
-        # AutoValue; such files always start $AutoValue_.....
-        # XepExcludedPaths is a regexp. If you need more paths - use | as
-        # separator.
-        "-XepExcludedPaths:.*/\\\\$$AutoValue_.*\\.java",
-        "-Xep:AlmostJavadoc:ERROR",
-        "-Xep:AlwaysThrows:ERROR",
-        "-Xep:AmbiguousMethodReference:ERROR",
-        # don't want to add dependency to errorprone
-        "-Xep:AnnotateFormatMethod:OFF",
-        "-Xep:ArgumentSelectionDefectChecker:ERROR",
-        "-Xep:ArrayAsKeyOfSetOrMap:ERROR",
-        "-Xep:ArrayEquals:ERROR",
-        "-Xep:ArrayFillIncompatibleType:ERROR",
-        "-Xep:ArrayHashCode:ERROR",
-        "-Xep:ArraysAsListPrimitiveArray:ERROR",
-        "-Xep:ArrayToString:ERROR",
-        "-Xep:AssertEqualsArgumentOrderChecker:WARN",
-        "-Xep:AssertionFailureIgnored:WARN",
-        "-Xep:AsyncCallableReturnsNull:ERROR",
-        "-Xep:AsyncFunctionReturnsNull:ERROR",
-        "-Xep:AutoValueConstructorOrderChecker:ERROR",
-        "-Xep:AutoValueFinalMethods:ERROR",
-        "-Xep:AutoValueImmutableFields:ERROR",
-        "-Xep:AutoValueSubclassLeaked:WARN",
-        "-Xep:BadAnnotationImplementation:ERROR",
-        "-Xep:BadComparable:ERROR",
-        "-Xep:BadImport:ERROR",
-        "-Xep:BadInstanceof:ERROR",
-        "-Xep:BadShiftAmount:ERROR",
-        "-Xep:BanSerializableRead:ERROR",
-        "-Xep:BigDecimalEquals:ERROR",
-        "-Xep:BigDecimalLiteralDouble:ERROR",
-        "-Xep:BoxedPrimitiveConstructor:ERROR",
-        "-Xep:BoxedPrimitiveEquality:ERROR",
-        "-Xep:BundleDeserializationCast:ERROR",
-        "-Xep:ByteBufferBackingArray:WARN",
-        "-Xep:CacheLoaderNull:ERROR",
-        "-Xep:CannotMockFinalClass:ERROR",
-        "-Xep:CanonicalDuration:ERROR",
-        "-Xep:CatchAndPrintStackTrace:ERROR",
-        "-Xep:CatchFail:ERROR",
-        "-Xep:ChainedAssertionLosesContext:ERROR",
-        "-Xep:ChainingConstructorIgnoresParameter:ERROR",
-        "-Xep:CharacterGetNumericValue:ERROR",
-        "-Xep:CheckNotNullMultipleTimes:ERROR",
-        "-Xep:CheckReturnValue:ERROR",
-        "-Xep:ClassCanBeStatic:ERROR",
-        "-Xep:ClassName:ERROR",
-        "-Xep:ClassNewInstance:ERROR",
-        "-Xep:CollectionIncompatibleType:ERROR",
-        "-Xep:CollectionToArraySafeParameter:ERROR",
-        "-Xep:CollectionUndefinedEquality:ERROR",
-        "-Xep:CollectorShouldNotUseState:ERROR",
-        "-Xep:ComparableAndComparator:ERROR",
-        "-Xep:ComparableType:ERROR",
-        "-Xep:CompareToZero:ERROR",
-        "-Xep:ComparingThisWithNull:ERROR",
-        "-Xep:ComparisonOutOfRange:ERROR",
-        "-Xep:CompatibleWithAnnotationMisuse:ERROR",
-        "-Xep:CompileTimeConstant:ERROR",
-        "-Xep:ComplexBooleanConstant:ERROR",
-        "-Xep:ComputeIfAbsentAmbiguousReference:ERROR",
-        "-Xep:ConditionalExpressionNumericPromotion:ERROR",
-        "-Xep:ConstantOverflow:ERROR",
-        "-Xep:DaggerProvidesNull:ERROR",
-        "-Xep:DangerousLiteralNull:ERROR",
-        "-Xep:DateChecker:ERROR",
-        "-Xep:DateFormatConstant:ERROR",
-        "-Xep:DeadException:ERROR",
-        "-Xep:DeadThread:ERROR",
-        "-Xep:DefaultCharset:ERROR",
-        "-Xep:DefaultPackage:ERROR",
-        "-Xep:DepAnn:ERROR",
-        "-Xep:DeprecatedVariable:ERROR",
-        "-Xep:DiscardedPostfixExpression:ERROR",
-        "-Xep:DoNotCall:ERROR",
-        "-Xep:DoNotCallSuggester:ERROR",
-        "-Xep:DoNotClaimAnnotations:ERROR",
-        "-Xep:DoNotMock:ERROR",
-        "-Xep:DoNotMockAutoValue:WARN",
-        "-Xep:DoubleBraceInitialization:ERROR",
-        "-Xep:DoubleCheckedLocking:ERROR",
-        "-Xep:DuplicateMapKeys:ERROR",
-        "-Xep:DurationFrom:ERROR",
-        "-Xep:DurationGetTemporalUnit:ERROR",
-        "-Xep:DurationTemporalUnit:ERROR",
-        "-Xep:DurationToLongTimeUnit:ERROR",
-        "-Xep:EmptyBlockTag:WARN",
-        "-Xep:EmptyCatch:ERROR",
-        "-Xep:EmptySetMultibindingContributions:ERROR",
-        "-Xep:EqualsGetClass:ERROR",
-        "-Xep:EqualsHashCode:ERROR",
-        "-Xep:EqualsIncompatibleType:ERROR",
-        "-Xep:EqualsNaN:ERROR",
-        "-Xep:EqualsNull:ERROR",
-        "-Xep:EqualsReference:ERROR",
-        "-Xep:EqualsUnsafeCast:ERROR",
-        "-Xep:EqualsUsingHashCode:ERROR",
-        "-Xep:EqualsWrongThing:ERROR",
-        "-Xep:ErroneousThreadPoolConstructorChecker:ERROR",
-        "-Xep:EscapedEntity:WARN",
-        "-Xep:ExpectedExceptionChecker:ERROR",
-        "-Xep:ExtendingJUnitAssert:ERROR",
-        "-Xep:ExtendsAutoValue:ERROR",
-        "-Xep:FallThrough:ERROR",
-        "-Xep:Finally:ERROR",
-        "-Xep:FloatCast:ERROR",
-        "-Xep:FloatingPointAssertionWithinEpsilon:ERROR",
-        "-Xep:FloatingPointLiteralPrecision:ERROR",
-        "-Xep:FloggerArgumentToString:ERROR",
-        "-Xep:FloggerFormatString:ERROR",
-        "-Xep:FloggerLogVarargs:ERROR",
-        "-Xep:FloggerSplitLogStatement:ERROR",
-        "-Xep:FloggerStringConcatenation:ERROR",
-        "-Xep:FormatString:ERROR",
-        "-Xep:FormatStringAnnotation:ERROR",
-        "-Xep:ForOverride:ERROR",
-        "-Xep:FragmentInjection:ERROR",
-        "-Xep:FragmentNotInstantiable:ERROR",
-        "-Xep:FromTemporalAccessor:ERROR",
-        "-Xep:FunctionalInterfaceClash:ERROR",
-        "-Xep:FunctionalInterfaceMethodChanged:ERROR",
-        "-Xep:FutureReturnValueIgnored:ERROR",
-        "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR",
-        "-Xep:GetClassOnAnnotation:ERROR",
-        "-Xep:GetClassOnClass:ERROR",
-        "-Xep:GetClassOnEnum:ERROR",
-        "-Xep:GuardedBy:ERROR",
-        "-Xep:GuiceAssistedInjectScoping:ERROR",
-        "-Xep:GuiceAssistedParameters:ERROR",
-        "-Xep:HashtableContains:ERROR",
-        "-Xep:HidingField:WARN",
-        "-Xep:IdentityBinaryExpression:ERROR",
-        "-Xep:IdentityHashMapBoxing:ERROR",
-        "-Xep:IdentityHashMapUsage:ERROR",
-        "-Xep:IgnoredPureGetter:ERROR",
-        "-Xep:Immutable:ERROR",
-        "-Xep:ImmutableAnnotationChecker:ERROR",
-        "-Xep:ImmutableEnumChecker:ERROR",
-        "-Xep:ImmutableModification:ERROR",
-        "-Xep:Incomparable:ERROR",
-        "-Xep:IncompatibleArgumentType:ERROR",
-        "-Xep:IncompatibleModifiers:ERROR",
-        "-Xep:InconsistentCapitalization:WARN",
-        "-Xep:InconsistentHashCode:ERROR",
-        "-Xep:IncrementInForLoopAndHeader:ERROR",
-        "-Xep:IndexOfChar:ERROR",
-        "-Xep:InexactVarargsConditional:ERROR",
-        "-Xep:InfiniteRecursion:ERROR",
-        "-Xep:InheritDoc:ERROR",
-        "-Xep:InjectOnConstructorOfAbstractClass:ERROR",
-        "-Xep:InlineFormatString:ERROR",
-        "-Xep:InlineMeInliner:ERROR",
-        # don't want to add dependency to errorprone
-        "-Xep:InlineMeSuggester:OFF",
-        "-Xep:InlineMeValidator:ERROR",
-        "-Xep:InputStreamSlowMultibyteRead:ERROR",
-        "-Xep:InsecureCryptoUsage:ERROR",
-        "-Xep:InstanceOfAndCastMatchWrongType:ERROR",
-        "-Xep:InstantTemporalUnit:ERROR",
-        "-Xep:IntLongMath:ERROR",
-        "-Xep:InvalidBlockTag:ERROR",
-        "-Xep:InvalidInlineTag:ERROR",
-        "-Xep:InvalidJavaTimeConstant:ERROR",
-        "-Xep:InvalidLink:ERROR",
-        "-Xep:InvalidParam:ERROR",
-        "-Xep:InvalidPatternSyntax:ERROR",
-        "-Xep:InvalidThrows:ERROR",
-        "-Xep:InvalidThrowsLink:ERROR",
-        "-Xep:InvalidTimeZoneID:ERROR",
-        "-Xep:InvalidZoneId:ERROR",
-        "-Xep:IsInstanceIncompatibleType:ERROR",
-        "-Xep:IsInstanceOfClass:ERROR",
-        "-Xep:IsLoggableTagLength:ERROR",
-        "-Xep:IterableAndIterator:ERROR",
-        "-Xep:IterablePathParameter:ERROR",
-        "-Xep:JavaDurationGetSecondsGetNano:ERROR",
-        "-Xep:JavaDurationWithNanos:ERROR",
-        "-Xep:JavaDurationWithSeconds:ERROR",
-        "-Xep:JavaInstantGetSecondsGetNano:ERROR",
-        "-Xep:JavaLangClash:ERROR",
-        "-Xep:JavaLocalDateTimeGetNano:ERROR",
-        "-Xep:JavaLocalTimeGetNano:ERROR",
-        "-Xep:JavaPeriodGetDays:ERROR",
-        "-Xep:JavaTimeDefaultTimeZone:ERROR",
-        "-Xep:JavaUtilDate:WARN",
-        "-Xep:JdkObsolete:ERROR",
-        "-Xep:JodaConstructors:ERROR",
-        "-Xep:JodaDateTimeConstants:ERROR",
-        "-Xep:JodaDurationWithMillis:ERROR",
-        "-Xep:JodaInstantWithMillis:ERROR",
-        "-Xep:JodaNewPeriod:ERROR",
-        "-Xep:JodaPlusMinusLong:ERROR",
-        "-Xep:JodaTimeConverterManager:ERROR",
-        "-Xep:JodaToSelf:ERROR",
-        "-Xep:JodaWithDurationAddedLong:ERROR",
-        "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR",
-        "-Xep:JUnit3TestNotRun:ERROR",
-        "-Xep:JUnit4ClassAnnotationNonStatic:ERROR",
-        "-Xep:JUnit4ClassUsedInJUnit3:ERROR",
-        "-Xep:JUnit4SetUpNotRun:ERROR",
-        "-Xep:JUnit4TearDownNotRun:ERROR",
-        "-Xep:JUnit4TestNotRun:ERROR",
-        "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR",
-        "-Xep:JUnitAmbiguousTestClass:ERROR",
-        "-Xep:JUnitAssertSameCheck:ERROR",
-        "-Xep:JUnitParameterMethodNotFound:ERROR",
-        "-Xep:LiteByteStringUtf8:ERROR",
-        "-Xep:LiteEnumValueOf:ERROR",
-        "-Xep:LiteProtoToString:ERROR",
-        "-Xep:LocalDateTemporalAmount:ERROR",
-        "-Xep:LockNotBeforeTry:ERROR",
-        "-Xep:LockOnBoxedPrimitive:ERROR",
-        "-Xep:LogicalAssignment:ERROR",
-        "-Xep:LongFloatConversion:ERROR",
-        "-Xep:LongLiteralLowerCaseSuffix:ERROR",
-        "-Xep:LoopConditionChecker:ERROR",
-        "-Xep:LoopOverCharArray:ERROR",
-        "-Xep:LossyPrimitiveCompare:ERROR",
-        "-Xep:MathAbsoluteRandom:ERROR",
-        "-Xep:MathRoundIntLong:ERROR",
-        "-Xep:MemoizeConstantVisitorStateLookups:ERROR",
-        "-Xep:MislabeledAndroidString:ERROR",
-        "-Xep:MissingCasesInEnumSwitch:ERROR",
-        "-Xep:MissingFail:ERROR",
-        "-Xep:MissingOverride:ERROR",
-        "-Xep:MissingSummary:WARN",
-        "-Xep:MissingSuperCall:ERROR",
-        "-Xep:MissingTestCall:ERROR",
-        "-Xep:MisusedDayOfYear:ERROR",
-        "-Xep:MisusedWeekYear:ERROR",
-        "-Xep:MixedDescriptors:ERROR",
-        "-Xep:MixedMutabilityReturnType:WARN",
-        "-Xep:MockitoUsage:ERROR",
-        "-Xep:ModifiedButNotUsed:ERROR",
-        "-Xep:ModifyCollectionInEnhancedForLoop:ERROR",
-        "-Xep:ModifyingCollectionWithItself:ERROR",
-        "-Xep:ModifySourceCollectionInStream:ERROR",
-        "-Xep:MultipleParallelOrSequentialCalls:ERROR",
-        "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR",
-        "-Xep:MustBeClosedChecker:ERROR",
-        "-Xep:MutableConstantField:ERROR",
-        # Java provides no good alternative
-        "-Xep:MutablePublicArray:OFF",
-        "-Xep:NarrowingCompoundAssignment:ERROR",
-        "-Xep:NCopiesOfChar:ERROR",
-        "-Xep:NestedInstanceOfConditions:ERROR",
-        "-Xep:NonAtomicVolatileUpdate:ERROR",
-        "-Xep:NonCanonicalStaticImport:ERROR",
-        "-Xep:NonCanonicalType:ERROR",
-        "-Xep:NonFinalCompileTimeConstant:ERROR",
-        "-Xep:NonOverridingEquals:ERROR",
-        "-Xep:NonRuntimeAnnotation:ERROR",
-        "-Xep:NullableConstructor:ERROR",
-        "-Xep:NullablePrimitive:ERROR",
-        "-Xep:NullablePrimitiveArray:ERROR",
-        "-Xep:NullableVoid:ERROR",
-        "-Xep:NullOptional:ERROR",
-        "-Xep:NullTernary:ERROR",
-        "-Xep:ObjectEqualsForPrimitives:ERROR",
-        "-Xep:ObjectsHashCodePrimitive:ERROR",
-        "-Xep:ObjectToString:ERROR",
-        "-Xep:OperatorPrecedence:ERROR",
-        "-Xep:OptionalEquality:ERROR",
-        "-Xep:OptionalMapToOptional:ERROR",
-        "-Xep:OptionalMapUnusedValue:ERROR",
-        "-Xep:OptionalNotPresent:ERROR",
-        "-Xep:OptionalOfRedundantMethod:ERROR",
-        "-Xep:OrphanedFormatString:ERROR",
-        "-Xep:OutlineNone:ERROR",
-        "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR",
-        "-Xep:Overrides:ERROR",
-        "-Xep:OverridesGuiceInjectableMethod:ERROR",
-        "-Xep:OverridesJavaxInjectableMethod:ERROR",
-        "-Xep:OverrideThrowableToString:ERROR",
-        "-Xep:PackageInfo:ERROR",
-        "-Xep:ParameterName:ERROR",
-        "-Xep:ParametersButNotParameterized:ERROR",
-        "-Xep:ParcelableCreator:ERROR",
-        "-Xep:PeriodFrom:ERROR",
-        "-Xep:PeriodGetTemporalUnit:ERROR",
-        "-Xep:PeriodTimeMath:ERROR",
-        "-Xep:PreconditionsCheckNotNullRepeated:ERROR",
-        "-Xep:PreconditionsInvalidPlaceholder:ERROR",
-        "-Xep:PreferredInterfaceType:OFF",
-        "-Xep:PrimitiveAtomicReference:ERROR",
-        "-Xep:PrivateSecurityContractProtoAccess:ERROR",
-        "-Xep:ProtectedMembersInFinalClass:ERROR",
-        "-Xep:ProtoBuilderReturnValueIgnored:ERROR",
-        "-Xep:ProtocolBufferOrdinal:ERROR",
-        "-Xep:ProtoDurationGetSecondsGetNano:ERROR",
-        "-Xep:ProtoFieldNullComparison:ERROR",
-        "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR",
-        "-Xep:ProtoRedundantSet:ERROR",
-        "-Xep:ProtoStringFieldReferenceEquality:ERROR",
-        "-Xep:ProtoTimestampGetSecondsGetNano:ERROR",
-        "-Xep:ProtoTruthMixedDescriptors:ERROR",
-        "-Xep:ProvidesMethodOutsideOfModule:ERROR",
-        "-Xep:RandomCast:ERROR",
-        "-Xep:RandomModInteger:ERROR",
-        "-Xep:ReachabilityFenceUsage:ERROR",
-        "-Xep:RectIntersectReturnValueIgnored:ERROR",
-        "-Xep:ReferenceEquality:ERROR",
-        "-Xep:RefersToDaggerCodegen:ERROR",
-        "-Xep:RemovedInJDK11:ERROR",
-        "-Xep:RequiredModifiers:ERROR",
-        "-Xep:RestrictedApiChecker:ERROR",
-        "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR",
-        "-Xep:ReturnFromVoid:ERROR",
-        "-Xep:ReturnValueIgnored:ERROR",
-        "-Xep:RxReturnValueIgnored:ERROR",
-        "-Xep:SameNameButDifferent:ERROR",
-        "-Xep:SelfAssignment:ERROR",
-        "-Xep:SelfComparison:ERROR",
-        "-Xep:SelfEquals:ERROR",
-        "-Xep:ShortCircuitBoolean:ERROR",
-        "-Xep:ShouldHaveEvenArgs:ERROR",
-        "-Xep:SizeGreaterThanOrEqualsZero:ERROR",
-        "-Xep:StaticAssignmentInConstructor:ERROR",
-        "-Xep:StaticGuardedByInstance:ERROR",
-        "-Xep:StaticMockMember:ERROR",
-        "-Xep:StaticQualifiedUsingExpression:ERROR",
-        "-Xep:StreamToString:ERROR",
-        "-Xep:StringBuilderInitWithChar:ERROR",
-        "-Xep:StringEquality:ERROR",
-        "-Xep:StringSplitter:WARN",
-        "-Xep:SubstringOfZero:ERROR",
-        "-Xep:SuppressWarningsDeprecated:ERROR",
-        "-Xep:SwigMemoryLeak:ERROR",
-        "-Xep:SynchronizeOnNonFinalField:ERROR",
-        "-Xep:TemporalAccessorGetChronoField:ERROR",
-        "-Xep:TestParametersNotInitialized:ERROR",
-        "-Xep:TheoryButNoTheories:ERROR",
-        "-Xep:ThreadJoinLoop:ERROR",
-        "-Xep:ThreadLocalUsage:ERROR",
-        "-Xep:ThreadPriorityCheck:ERROR",
-        "-Xep:ThreeLetterTimeZoneID:WARN",
-        "-Xep:ThrowIfUncheckedKnownChecked:ERROR",
-        "-Xep:ThrowNull:ERROR",
-        "-Xep:TimeUnitConversionChecker:ERROR",
-        "-Xep:ToStringReturnsNull:ERROR",
-        "-Xep:TreeToString:ERROR",
-        "-Xep:TruthAssertExpected:ERROR",
-        "-Xep:TruthConstantAsserts:ERROR",
-        "-Xep:TruthGetOrDefault:ERROR",
-        "-Xep:TruthIncompatibleType:ERROR",
-        "-Xep:TruthSelfEquals:ERROR",
-        "-Xep:TryFailThrowable:ERROR",
-        "-Xep:TypeEquals:ERROR",
-        "-Xep:TypeNameShadowing:ERROR",
-        "-Xep:TypeParameterQualifier:ERROR",
-        "-Xep:TypeParameterShadowing:ERROR",
-        "-Xep:TypeParameterUnusedInFormals:ERROR",
-        "-Xep:UndefinedEquals:WARN",
-        "-Xep:UnescapedEntity:WARN",
-        "-Xep:UnnecessaryAssignment:ERROR",
-        "-Xep:UnnecessaryCheckNotNull:ERROR",
-        "-Xep:UnnecessaryLambda:ERROR",
-        "-Xep:UnnecessaryMethodInvocationMatcher:ERROR",
-        "-Xep:UnnecessaryMethodReference:ERROR",
-        "-Xep:UnnecessaryParentheses:ERROR",
-        "-Xep:UnnecessaryTypeArgument:ERROR",
-        "-Xep:UnrecognisedJavadocTag:ERROR",
-        "-Xep:UnsafeFinalization:ERROR",
-        "-Xep:UnsafeReflectiveConstructionCast:ERROR",
-        "-Xep:UnsynchronizedOverridesSynchronized:ERROR",
-        "-Xep:UnusedAnonymousClass:ERROR",
-        "-Xep:UnusedCollectionModifiedInPlace:ERROR",
-        "-Xep:UnusedException:ERROR",
-        "-Xep:UnusedMethod:WARN",
-        "-Xep:UnusedNestedClass:ERROR",
-        "-Xep:UnusedVariable:ERROR",
-        "-Xep:URLEqualsHashCode:ERROR",
-        "-Xep:UseBinds:ERROR",
-        "-Xep:UseCorrectAssertInTests:ERROR",
-        "-Xep:VariableNameSameAsType:ERROR",
-        "-Xep:VarTypeName:ERROR",
-        "-Xep:WaitNotInLoop:ERROR",
-        "-Xep:WakelockReleasedDangerously:ERROR",
-        "-Xep:WildcardImport:ERROR",
-        "-Xep:WithSignatureDiscouraged:ERROR",
-        "-Xep:WrongOneof:ERROR",
-        "-Xep:XorPower:ERROR",
-        "-Xep:ZoneIdOfZ:ERROR",
+    "-XepDisableWarningsInGeneratedCode",
+    # The XepDisableWarningsInGeneratedCode disables only warnings, but
+    # not errors. We should manually exclude all files generated by
+    # AutoValue; such files always start $AutoValue_.....
+    # XepExcludedPaths is a regexp. If you need more paths - use | as
+    # separator.
+    "-XepExcludedPaths:.*/\\\\$$AutoValue_.*\\.java",
+    "-Xep:AlmostJavadoc:ERROR",
+    "-Xep:AlwaysThrows:ERROR",
+    "-Xep:AmbiguousMethodReference:ERROR",
+    # don't want to add dependency to errorprone
+    "-Xep:AnnotateFormatMethod:OFF",
+    "-Xep:ArgumentSelectionDefectChecker:ERROR",
+    "-Xep:ArrayAsKeyOfSetOrMap:ERROR",
+    "-Xep:ArrayEquals:ERROR",
+    "-Xep:ArrayFillIncompatibleType:ERROR",
+    "-Xep:ArrayHashCode:ERROR",
+    "-Xep:ArraysAsListPrimitiveArray:ERROR",
+    "-Xep:ArrayToString:ERROR",
+    "-Xep:AssertEqualsArgumentOrderChecker:WARN",
+    "-Xep:AssertionFailureIgnored:WARN",
+    "-Xep:AsyncCallableReturnsNull:ERROR",
+    "-Xep:AsyncFunctionReturnsNull:ERROR",
+    "-Xep:AutoValueConstructorOrderChecker:ERROR",
+    "-Xep:AutoValueFinalMethods:ERROR",
+    "-Xep:AutoValueImmutableFields:ERROR",
+    "-Xep:AutoValueSubclassLeaked:WARN",
+    "-Xep:BadAnnotationImplementation:ERROR",
+    "-Xep:BadComparable:ERROR",
+    "-Xep:BadImport:ERROR",
+    "-Xep:BadInstanceof:ERROR",
+    "-Xep:BadShiftAmount:ERROR",
+    "-Xep:BanSerializableRead:ERROR",
+    "-Xep:BigDecimalEquals:ERROR",
+    "-Xep:BigDecimalLiteralDouble:ERROR",
+    "-Xep:BoxedPrimitiveConstructor:ERROR",
+    "-Xep:BoxedPrimitiveEquality:ERROR",
+    "-Xep:BundleDeserializationCast:ERROR",
+    "-Xep:ByteBufferBackingArray:WARN",
+    "-Xep:CacheLoaderNull:ERROR",
+    "-Xep:CannotMockFinalClass:ERROR",
+    "-Xep:CanonicalDuration:ERROR",
+    "-Xep:CatchAndPrintStackTrace:ERROR",
+    "-Xep:CatchFail:ERROR",
+    "-Xep:ChainedAssertionLosesContext:ERROR",
+    "-Xep:ChainingConstructorIgnoresParameter:ERROR",
+    "-Xep:CharacterGetNumericValue:ERROR",
+    "-Xep:CheckNotNullMultipleTimes:ERROR",
+    "-Xep:CheckReturnValue:ERROR",
+    "-Xep:ClassCanBeStatic:ERROR",
+    "-Xep:ClassName:ERROR",
+    "-Xep:ClassNewInstance:ERROR",
+    "-Xep:CollectionIncompatibleType:ERROR",
+    "-Xep:CollectionToArraySafeParameter:ERROR",
+    "-Xep:CollectionUndefinedEquality:ERROR",
+    "-Xep:CollectorShouldNotUseState:ERROR",
+    "-Xep:ComparableAndComparator:ERROR",
+    "-Xep:ComparableType:ERROR",
+    "-Xep:CompareToZero:ERROR",
+    "-Xep:ComparingThisWithNull:ERROR",
+    "-Xep:ComparisonOutOfRange:ERROR",
+    "-Xep:CompatibleWithAnnotationMisuse:ERROR",
+    "-Xep:CompileTimeConstant:ERROR",
+    "-Xep:ComplexBooleanConstant:ERROR",
+    "-Xep:ComputeIfAbsentAmbiguousReference:ERROR",
+    "-Xep:ConditionalExpressionNumericPromotion:ERROR",
+    "-Xep:ConstantOverflow:ERROR",
+    "-Xep:DaggerProvidesNull:ERROR",
+    "-Xep:DangerousLiteralNull:ERROR",
+    "-Xep:DateChecker:ERROR",
+    "-Xep:DateFormatConstant:ERROR",
+    "-Xep:DeadException:ERROR",
+    "-Xep:DeadThread:ERROR",
+    "-Xep:DefaultCharset:ERROR",
+    "-Xep:DefaultPackage:ERROR",
+    "-Xep:DepAnn:ERROR",
+    "-Xep:DeprecatedVariable:ERROR",
+    "-Xep:DiscardedPostfixExpression:ERROR",
+    "-Xep:DoNotCall:ERROR",
+    "-Xep:DoNotCallSuggester:ERROR",
+    "-Xep:DoNotClaimAnnotations:ERROR",
+    "-Xep:DoNotMock:ERROR",
+    "-Xep:DoNotMockAutoValue:WARN",
+    "-Xep:DoubleBraceInitialization:ERROR",
+    "-Xep:DoubleCheckedLocking:ERROR",
+    "-Xep:DuplicateMapKeys:ERROR",
+    "-Xep:DurationFrom:ERROR",
+    "-Xep:DurationGetTemporalUnit:ERROR",
+    "-Xep:DurationTemporalUnit:ERROR",
+    "-Xep:DurationToLongTimeUnit:ERROR",
+    "-Xep:EmptyBlockTag:WARN",
+    "-Xep:EmptyCatch:ERROR",
+    "-Xep:EmptySetMultibindingContributions:ERROR",
+    "-Xep:EqualsGetClass:ERROR",
+    "-Xep:EqualsHashCode:ERROR",
+    "-Xep:EqualsIncompatibleType:ERROR",
+    "-Xep:EqualsNaN:ERROR",
+    "-Xep:EqualsNull:ERROR",
+    "-Xep:EqualsReference:ERROR",
+    "-Xep:EqualsUnsafeCast:ERROR",
+    "-Xep:EqualsUsingHashCode:ERROR",
+    "-Xep:EqualsWrongThing:ERROR",
+    "-Xep:ErroneousThreadPoolConstructorChecker:ERROR",
+    "-Xep:EscapedEntity:WARN",
+    "-Xep:ExpectedExceptionChecker:ERROR",
+    "-Xep:ExtendingJUnitAssert:ERROR",
+    "-Xep:ExtendsAutoValue:ERROR",
+    "-Xep:FallThrough:ERROR",
+    "-Xep:Finally:ERROR",
+    "-Xep:FloatCast:ERROR",
+    "-Xep:FloatingPointAssertionWithinEpsilon:ERROR",
+    "-Xep:FloatingPointLiteralPrecision:ERROR",
+    "-Xep:FloggerArgumentToString:ERROR",
+    "-Xep:FloggerFormatString:ERROR",
+    "-Xep:FloggerLogVarargs:ERROR",
+    "-Xep:FloggerSplitLogStatement:ERROR",
+    "-Xep:FloggerStringConcatenation:ERROR",
+    "-Xep:FormatString:ERROR",
+    "-Xep:FormatStringAnnotation:ERROR",
+    "-Xep:ForOverride:ERROR",
+    "-Xep:FragmentInjection:ERROR",
+    "-Xep:FragmentNotInstantiable:ERROR",
+    "-Xep:FromTemporalAccessor:ERROR",
+    "-Xep:FunctionalInterfaceClash:ERROR",
+    "-Xep:FunctionalInterfaceMethodChanged:ERROR",
+    "-Xep:FutureReturnValueIgnored:ERROR",
+    "-Xep:FuturesGetCheckedIllegalExceptionType:ERROR",
+    "-Xep:GetClassOnAnnotation:ERROR",
+    "-Xep:GetClassOnClass:ERROR",
+    "-Xep:GetClassOnEnum:ERROR",
+    "-Xep:GuardedBy:ERROR",
+    "-Xep:GuiceAssistedInjectScoping:ERROR",
+    "-Xep:GuiceAssistedParameters:ERROR",
+    "-Xep:HashtableContains:ERROR",
+    "-Xep:HidingField:WARN",
+    "-Xep:IdentityBinaryExpression:ERROR",
+    "-Xep:IdentityHashMapBoxing:ERROR",
+    "-Xep:IdentityHashMapUsage:ERROR",
+    "-Xep:IgnoredPureGetter:ERROR",
+    "-Xep:Immutable:ERROR",
+    "-Xep:ImmutableAnnotationChecker:ERROR",
+    "-Xep:ImmutableEnumChecker:ERROR",
+    "-Xep:ImmutableModification:ERROR",
+    "-Xep:Incomparable:ERROR",
+    "-Xep:IncompatibleArgumentType:ERROR",
+    "-Xep:IncompatibleModifiers:ERROR",
+    "-Xep:InconsistentCapitalization:WARN",
+    "-Xep:InconsistentHashCode:ERROR",
+    "-Xep:IncrementInForLoopAndHeader:ERROR",
+    "-Xep:IndexOfChar:ERROR",
+    "-Xep:InexactVarargsConditional:ERROR",
+    "-Xep:InfiniteRecursion:ERROR",
+    "-Xep:InheritDoc:ERROR",
+    "-Xep:InjectOnConstructorOfAbstractClass:ERROR",
+    "-Xep:InlineFormatString:ERROR",
+    "-Xep:InlineMeInliner:ERROR",
+    # don't want to add dependency to errorprone
+    "-Xep:InlineMeSuggester:OFF",
+    "-Xep:InlineMeValidator:ERROR",
+    "-Xep:InputStreamSlowMultibyteRead:ERROR",
+    "-Xep:InsecureCryptoUsage:ERROR",
+    "-Xep:InstanceOfAndCastMatchWrongType:ERROR",
+    "-Xep:InstantTemporalUnit:ERROR",
+    "-Xep:IntLongMath:ERROR",
+    "-Xep:InvalidBlockTag:ERROR",
+    "-Xep:InvalidInlineTag:ERROR",
+    "-Xep:InvalidJavaTimeConstant:ERROR",
+    "-Xep:InvalidLink:ERROR",
+    "-Xep:InvalidParam:ERROR",
+    "-Xep:InvalidPatternSyntax:ERROR",
+    "-Xep:InvalidThrows:ERROR",
+    "-Xep:InvalidThrowsLink:ERROR",
+    "-Xep:InvalidTimeZoneID:ERROR",
+    "-Xep:InvalidZoneId:ERROR",
+    "-Xep:IsInstanceIncompatibleType:ERROR",
+    "-Xep:IsInstanceOfClass:ERROR",
+    "-Xep:IsLoggableTagLength:ERROR",
+    "-Xep:IterableAndIterator:ERROR",
+    "-Xep:IterablePathParameter:ERROR",
+    "-Xep:JavaDurationGetSecondsGetNano:ERROR",
+    "-Xep:JavaDurationWithNanos:ERROR",
+    "-Xep:JavaDurationWithSeconds:ERROR",
+    "-Xep:JavaInstantGetSecondsGetNano:ERROR",
+    "-Xep:JavaLangClash:ERROR",
+    "-Xep:JavaLocalDateTimeGetNano:ERROR",
+    "-Xep:JavaLocalTimeGetNano:ERROR",
+    "-Xep:JavaPeriodGetDays:ERROR",
+    "-Xep:JavaTimeDefaultTimeZone:ERROR",
+    "-Xep:JavaUtilDate:WARN",
+    "-Xep:JdkObsolete:ERROR",
+    "-Xep:JodaConstructors:ERROR",
+    "-Xep:JodaDateTimeConstants:ERROR",
+    "-Xep:JodaDurationWithMillis:ERROR",
+    "-Xep:JodaInstantWithMillis:ERROR",
+    "-Xep:JodaNewPeriod:ERROR",
+    "-Xep:JodaPlusMinusLong:ERROR",
+    "-Xep:JodaTimeConverterManager:ERROR",
+    "-Xep:JodaToSelf:ERROR",
+    "-Xep:JodaWithDurationAddedLong:ERROR",
+    "-Xep:JUnit3FloatingPointComparisonWithoutDelta:ERROR",
+    "-Xep:JUnit3TestNotRun:ERROR",
+    "-Xep:JUnit4ClassAnnotationNonStatic:ERROR",
+    "-Xep:JUnit4ClassUsedInJUnit3:ERROR",
+    "-Xep:JUnit4SetUpNotRun:ERROR",
+    "-Xep:JUnit4TearDownNotRun:ERROR",
+    "-Xep:JUnit4TestNotRun:ERROR",
+    "-Xep:JUnit4TestsNotRunWithinEnclosed:ERROR",
+    "-Xep:JUnitAmbiguousTestClass:ERROR",
+    "-Xep:JUnitAssertSameCheck:ERROR",
+    "-Xep:JUnitParameterMethodNotFound:ERROR",
+    "-Xep:LiteByteStringUtf8:ERROR",
+    "-Xep:LiteEnumValueOf:ERROR",
+    "-Xep:LiteProtoToString:ERROR",
+    "-Xep:LocalDateTemporalAmount:ERROR",
+    "-Xep:LockNotBeforeTry:ERROR",
+    "-Xep:LockOnBoxedPrimitive:ERROR",
+    "-Xep:LogicalAssignment:ERROR",
+    "-Xep:LongFloatConversion:ERROR",
+    "-Xep:LongLiteralLowerCaseSuffix:ERROR",
+    "-Xep:LoopConditionChecker:ERROR",
+    "-Xep:LoopOverCharArray:ERROR",
+    "-Xep:LossyPrimitiveCompare:ERROR",
+    "-Xep:MathAbsoluteRandom:ERROR",
+    "-Xep:MathRoundIntLong:ERROR",
+    "-Xep:MemoizeConstantVisitorStateLookups:ERROR",
+    "-Xep:MislabeledAndroidString:ERROR",
+    "-Xep:MissingCasesInEnumSwitch:ERROR",
+    "-Xep:MissingFail:ERROR",
+    "-Xep:MissingOverride:ERROR",
+    "-Xep:MissingSummary:WARN",
+    "-Xep:MissingSuperCall:ERROR",
+    "-Xep:MissingTestCall:ERROR",
+    "-Xep:MisusedDayOfYear:ERROR",
+    "-Xep:MisusedWeekYear:ERROR",
+    "-Xep:MixedDescriptors:ERROR",
+    "-Xep:MixedMutabilityReturnType:WARN",
+    "-Xep:MockitoUsage:ERROR",
+    "-Xep:ModifiedButNotUsed:ERROR",
+    "-Xep:ModifyCollectionInEnhancedForLoop:ERROR",
+    "-Xep:ModifyingCollectionWithItself:ERROR",
+    "-Xep:ModifySourceCollectionInStream:ERROR",
+    "-Xep:MultipleParallelOrSequentialCalls:ERROR",
+    "-Xep:MultipleUnaryOperatorsInMethodCall:ERROR",
+    "-Xep:MustBeClosedChecker:ERROR",
+    "-Xep:MutableConstantField:ERROR",
+    # Java provides no good alternative
+    "-Xep:MutablePublicArray:OFF",
+    "-Xep:NarrowingCompoundAssignment:ERROR",
+    "-Xep:NCopiesOfChar:ERROR",
+    "-Xep:NestedInstanceOfConditions:ERROR",
+    "-Xep:NonAtomicVolatileUpdate:ERROR",
+    "-Xep:NonCanonicalStaticImport:ERROR",
+    "-Xep:NonCanonicalType:ERROR",
+    "-Xep:NonFinalCompileTimeConstant:ERROR",
+    "-Xep:NonOverridingEquals:ERROR",
+    "-Xep:NonRuntimeAnnotation:ERROR",
+    "-Xep:NullableConstructor:ERROR",
+    "-Xep:NullablePrimitive:ERROR",
+    "-Xep:NullablePrimitiveArray:ERROR",
+    "-Xep:NullableVoid:ERROR",
+    "-Xep:NullOptional:ERROR",
+    "-Xep:NullTernary:ERROR",
+    "-Xep:ObjectEqualsForPrimitives:ERROR",
+    "-Xep:ObjectsHashCodePrimitive:ERROR",
+    "-Xep:ObjectToString:ERROR",
+    "-Xep:OperatorPrecedence:ERROR",
+    "-Xep:OptionalEquality:ERROR",
+    "-Xep:OptionalMapToOptional:ERROR",
+    "-Xep:OptionalMapUnusedValue:ERROR",
+    "-Xep:OptionalNotPresent:ERROR",
+    "-Xep:OptionalOfRedundantMethod:ERROR",
+    "-Xep:OrphanedFormatString:ERROR",
+    "-Xep:OutlineNone:ERROR",
+    "-Xep:OverlappingQualifierAndScopeAnnotation:ERROR",
+    "-Xep:Overrides:ERROR",
+    "-Xep:OverridesGuiceInjectableMethod:ERROR",
+    "-Xep:OverridesJavaxInjectableMethod:ERROR",
+    "-Xep:OverrideThrowableToString:ERROR",
+    "-Xep:PackageInfo:ERROR",
+    "-Xep:ParameterName:ERROR",
+    "-Xep:ParametersButNotParameterized:ERROR",
+    "-Xep:ParcelableCreator:ERROR",
+    "-Xep:PeriodFrom:ERROR",
+    "-Xep:PeriodGetTemporalUnit:ERROR",
+    "-Xep:PeriodTimeMath:ERROR",
+    "-Xep:PreconditionsCheckNotNullRepeated:ERROR",
+    "-Xep:PreconditionsInvalidPlaceholder:ERROR",
+    "-Xep:PreferredInterfaceType:OFF",
+    "-Xep:PrimitiveAtomicReference:ERROR",
+    "-Xep:PrivateSecurityContractProtoAccess:ERROR",
+    "-Xep:ProtectedMembersInFinalClass:ERROR",
+    "-Xep:ProtoBuilderReturnValueIgnored:ERROR",
+    "-Xep:ProtocolBufferOrdinal:ERROR",
+    "-Xep:ProtoDurationGetSecondsGetNano:ERROR",
+    "-Xep:ProtoFieldNullComparison:ERROR",
+    "-Xep:ProtoFieldPreconditionsCheckNotNull:ERROR",
+    "-Xep:ProtoRedundantSet:ERROR",
+    "-Xep:ProtoStringFieldReferenceEquality:ERROR",
+    "-Xep:ProtoTimestampGetSecondsGetNano:ERROR",
+    "-Xep:ProtoTruthMixedDescriptors:ERROR",
+    "-Xep:ProvidesMethodOutsideOfModule:ERROR",
+    "-Xep:RandomCast:ERROR",
+    "-Xep:RandomModInteger:ERROR",
+    "-Xep:ReachabilityFenceUsage:ERROR",
+    "-Xep:RectIntersectReturnValueIgnored:ERROR",
+    "-Xep:ReferenceEquality:ERROR",
+    "-Xep:RefersToDaggerCodegen:ERROR",
+    "-Xep:RemovedInJDK11:ERROR",
+    "-Xep:RequiredModifiers:ERROR",
+    "-Xep:RestrictedApiChecker:ERROR",
+    "-Xep:RethrowReflectiveOperationExceptionAsLinkageError:ERROR",
+    "-Xep:ReturnFromVoid:ERROR",
+    "-Xep:ReturnValueIgnored:ERROR",
+    "-Xep:RxReturnValueIgnored:ERROR",
+    "-Xep:SameNameButDifferent:ERROR",
+    "-Xep:SelfAssignment:ERROR",
+    "-Xep:SelfComparison:ERROR",
+    "-Xep:SelfEquals:ERROR",
+    "-Xep:ShortCircuitBoolean:ERROR",
+    "-Xep:ShouldHaveEvenArgs:ERROR",
+    "-Xep:SizeGreaterThanOrEqualsZero:ERROR",
+    "-Xep:StaticAssignmentInConstructor:ERROR",
+    "-Xep:StaticGuardedByInstance:ERROR",
+    "-Xep:StaticMockMember:ERROR",
+    "-Xep:StaticQualifiedUsingExpression:ERROR",
+    "-Xep:StreamToString:ERROR",
+    "-Xep:StringBuilderInitWithChar:ERROR",
+    "-Xep:StringEquality:ERROR",
+    "-Xep:StringSplitter:WARN",
+    "-Xep:SubstringOfZero:ERROR",
+    "-Xep:SuppressWarningsDeprecated:ERROR",
+    "-Xep:SwigMemoryLeak:ERROR",
+    "-Xep:SynchronizeOnNonFinalField:ERROR",
+    "-Xep:TemporalAccessorGetChronoField:ERROR",
+    "-Xep:TestParametersNotInitialized:ERROR",
+    "-Xep:TheoryButNoTheories:ERROR",
+    "-Xep:ThreadJoinLoop:ERROR",
+    "-Xep:ThreadLocalUsage:ERROR",
+    "-Xep:ThreadPriorityCheck:ERROR",
+    "-Xep:ThreeLetterTimeZoneID:WARN",
+    "-Xep:ThrowIfUncheckedKnownChecked:ERROR",
+    "-Xep:ThrowNull:ERROR",
+    "-Xep:TimeUnitConversionChecker:ERROR",
+    "-Xep:ToStringReturnsNull:ERROR",
+    "-Xep:TreeToString:ERROR",
+    "-Xep:TruthAssertExpected:ERROR",
+    "-Xep:TruthConstantAsserts:ERROR",
+    "-Xep:TruthGetOrDefault:ERROR",
+    "-Xep:TruthIncompatibleType:ERROR",
+    "-Xep:TruthSelfEquals:ERROR",
+    "-Xep:TryFailThrowable:ERROR",
+    "-Xep:TypeEquals:ERROR",
+    "-Xep:TypeNameShadowing:ERROR",
+    "-Xep:TypeParameterQualifier:ERROR",
+    "-Xep:TypeParameterShadowing:ERROR",
+    "-Xep:TypeParameterUnusedInFormals:ERROR",
+    "-Xep:UndefinedEquals:WARN",
+    "-Xep:UnescapedEntity:WARN",
+    "-Xep:UnnecessaryAssignment:ERROR",
+    "-Xep:UnnecessaryCheckNotNull:ERROR",
+    "-Xep:UnnecessaryLambda:ERROR",
+    "-Xep:UnnecessaryMethodInvocationMatcher:ERROR",
+    "-Xep:UnnecessaryMethodReference:ERROR",
+    "-Xep:UnnecessaryParentheses:ERROR",
+    "-Xep:UnnecessaryTypeArgument:ERROR",
+    "-Xep:UnrecognisedJavadocTag:ERROR",
+    "-Xep:UnsafeFinalization:ERROR",
+    "-Xep:UnsafeReflectiveConstructionCast:ERROR",
+    "-Xep:UnsynchronizedOverridesSynchronized:ERROR",
+    "-Xep:UnusedAnonymousClass:ERROR",
+    "-Xep:UnusedCollectionModifiedInPlace:ERROR",
+    "-Xep:UnusedException:ERROR",
+    "-Xep:UnusedMethod:WARN",
+    "-Xep:UnusedNestedClass:ERROR",
+    "-Xep:UnusedVariable:ERROR",
+    "-Xep:URLEqualsHashCode:ERROR",
+    "-Xep:UseBinds:ERROR",
+    "-Xep:UseCorrectAssertInTests:ERROR",
+    "-Xep:VariableNameSameAsType:ERROR",
+    "-Xep:VarTypeName:ERROR",
+    "-Xep:WaitNotInLoop:ERROR",
+    "-Xep:WakelockReleasedDangerously:ERROR",
+    "-Xep:WildcardImport:ERROR",
+    "-Xep:WithSignatureDiscouraged:ERROR",
+    "-Xep:WrongOneof:ERROR",
+    "-Xep:XorPower:ERROR",
+    "-Xep:ZoneIdOfZ:ERROR",
 ]
 
-
-exclude_in_tests = ["-Xep:EmptyBlockTag:WARN",
-                    "-Xep:MissingSummary:WARN"]
+exclude_in_tests = [
+    "-Xep:EmptyBlockTag:WARN",
+    "-Xep:MissingSummary:WARN",
+]
 
 java_package_configuration(
     name = "error_prone",
@@ -436,7 +437,7 @@
 
 java_package_configuration(
     name = "error_prone_tests",
-    javacopts = [ check for check in errorprone_checks if check not in exclude_in_tests],
+    javacopts = [check for check in errorprone_checks if check not in exclude_in_tests],
     packages = ["error_prone_packages_test"],
 )
 
diff --git a/tools/jgit-ee8/BUILD b/tools/jgit-ee8/BUILD
new file mode 100644
index 0000000..f6681cc
--- /dev/null
+++ b/tools/jgit-ee8/BUILD
@@ -0,0 +1,55 @@
+load("@rules_shell//shell:sh_test.bzl", "sh_test")
+
+sh_test(
+    name = "generated_srcs_test",
+    srcs = ["@com_googlesource_gerrit_bazlets//tools:generated_srcs_test.sh"],
+    args = [
+        "--forbid",
+        "jakarta\\.servlet",
+        "--forbid",
+        "org\\.eclipse\\.jetty\\.ee10\\.servlet",
+        "--forbid",
+        "org\\.eclipse\\.jgit\\..*\\.ee8",
+        "--require-if-source",
+        "jakarta\\.servlet",
+        "javax\\.servlet",
+        "--module",
+        "org.eclipse.jgit.http.server/src/",
+        "$(location //org.eclipse.jgit.http.server.ee8:jgit-http-server-ee8-srcs)",
+        "$(locations //org.eclipse.jgit.http.server:srcs)",
+        "--module",
+        "org.eclipse.jgit.lfs.server/src/",
+        "$(location //org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs)",
+        "$(locations //org.eclipse.jgit.lfs.server:srcs)",
+        "--module",
+        "org.eclipse.jgit.junit.http/src/",
+        "$(location //org.eclipse.jgit.junit.http:junit-http-ee8-srcs)",
+        "$(locations //org.eclipse.jgit.junit.http:ee8-transform-srcs)",
+        "--module",
+        "org.eclipse.jgit.http.test/src/",
+        "$(location //org.eclipse.jgit.http.test.ee8:helpers-srcs)",
+        "$(locations //org.eclipse.jgit.http.test:helper-srcs)",
+        "--module",
+        "org.eclipse.jgit.http.test/tst/",
+        "$(location //org.eclipse.jgit.http.test.ee8:test-srcs)",
+        "$(locations //org.eclipse.jgit.http.test:test-srcs)",
+        "--module",
+        "org.eclipse.jgit.lfs.server.test/tst/",
+        "$(location //org.eclipse.jgit.lfs.server.test.ee8:test-srcs)",
+        "$(locations //org.eclipse.jgit.lfs.server.test:test-srcs)",
+    ],
+    data = [
+        "//org.eclipse.jgit.http.server.ee8:jgit-http-server-ee8-srcs",
+        "//org.eclipse.jgit.http.server:srcs",
+        "//org.eclipse.jgit.http.test.ee8:helpers-srcs",
+        "//org.eclipse.jgit.http.test.ee8:test-srcs",
+        "//org.eclipse.jgit.http.test:helper-srcs",
+        "//org.eclipse.jgit.http.test:test-srcs",
+        "//org.eclipse.jgit.junit.http:ee8-transform-srcs",
+        "//org.eclipse.jgit.junit.http:junit-http-ee8-srcs",
+        "//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8-srcs",
+        "//org.eclipse.jgit.lfs.server:srcs",
+        "//org.eclipse.jgit.lfs.server.test.ee8:test-srcs",
+        "//org.eclipse.jgit.lfs.server.test:test-srcs",
+    ],
+)
diff --git a/tools/jgit-ee8/README.md b/tools/jgit-ee8/README.md
new file mode 100644
index 0000000..7bb2f47
--- /dev/null
+++ b/tools/jgit-ee8/README.md
@@ -0,0 +1,69 @@
+# JGit EE8 Bazel bridge
+
+This package contains the Bazel-only bridge for source consumers that still run
+on EE8 and `javax.servlet` while JGit master uses `jakarta.servlet`.
+
+JGit hosts this bridge because Gerrit is a known downstream that consumes JGit
+from source through a git submodule and still runs Jetty 12 EE8. Keeping the
+bridge in JGit lets Gerrit track JGit master and avoids maintaining a long-lived
+servlet-4 branch just for Gerrit. That branch was never a stable JGit release
+line, so it is not a sustainable way for Gerrit to receive JGit maintenance
+updates.
+
+The bridge intentionally keeps the original JGit package names. It rewrites only
+servlet API references from `jakarta.servlet` to `javax.servlet`, then compiles
+generated jars from the rewritten source jars.
+
+Generated targets:
+
+* `//org.eclipse.jgit.http.server.ee8:jgit-servlet-ee8`
+* `//org.eclipse.jgit.lfs.server.ee8:jgit-lfs-server-ee8`
+
+Do not put one of these generated jars and its canonical Jakarta counterpart on
+the same classpath. They contain the same JGit classes.
+
+This is intentionally limited to source generation, build, and test. It does
+not add Tycho, p2, or Maven Central publication machinery yet.
+
+Run:
+
+```sh
+bazelisk test \
+  //tools/jgit-ee8:generated_srcs_test \
+  //org.eclipse.jgit.junit.http.ee8:tests
+```
+
+`//tools/jgit-ee8:generated_srcs_test` checks:
+
+* generated sources are derived from the canonical source filegroups
+* generated srcjar entries use Java package paths
+* generated sources preserve line counts for debugger breakpoints
+* generated sources contain `javax.servlet`, not `jakarta.servlet`
+* generated sources do not move JGit classes to an `.ee8` package
+
+The dedicated `org.eclipse.jgit.*.ee8` targets follow the Jetty 12 EE8 testing
+model in a smaller form. Jetty generates EE8 main and test sources from the
+canonical newer-EE modules and then runs the EE8 tests in the EE8 module graph.
+JGit does the same for the servlet-facing tests: the HTTP/LFS test sources and
+shared `junit-http` helpers are transformed to `javax.servlet`, wired to Jetty
+EE8 test dependencies, and run against the generated EE8 JGit jars.
+
+`//org.eclipse.jgit.http.test.ee8:server_unit` is a fast, focused target for the
+three HTTP server utility tests. It is not part of the default EE8 suite because
+those classes already run under `//org.eclipse.jgit.http.test.ee8:http`.
+
+The test rewrite rules also map Jetty test helper imports from
+`org.eclipse.jetty.ee10.servlet` to the Jetty EE8 packages needed by the tests.
+They are intentionally test-only and separate from the production
+`jakarta.servlet` to `javax.servlet` rules.
+
+Next steps:
+
+* Keep this source-consumer bridge while Gerrit runs on Jetty 12 EE8.
+* Reuse these targets for other Bazel source consumers that need EE8 output.
+* Move the generated-test JUnit helper to bazlets only if more generated-test
+  users need the same split between suite source labels and compiled sources.
+* Add Maven/Tycho/p2 generation only when a non-Bazel consumer needs published
+  EE8 artifacts.
+* Keep the canonical `srcs` filegroups aligned with each servlet-facing
+  `java_library` so new Java sources are transformed automatically.