diff --git a/flake.lock b/flake.lock index c328b6a..9acf76d 100644 --- a/flake.lock +++ b/flake.lock @@ -229,6 +229,26 @@ "url": "https://git@git.lix.systems/lix-project/lix" } }, + "nix-gerrit": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1720472191, + "narHash": "sha256-v42zXC8syDpAuF3cdpwCxU9DsbcDmYVKCfkDq4ZBufU=", + "ref": "refs/heads/main", + "rev": "eb589c659e494e5fcb5b47b75be9984ae87a500a", + "revCount": 4, + "type": "git", + "url": "https://git.lix.systems/the-distro/nix-gerrit.git" + }, + "original": { + "type": "git", + "url": "https://git.lix.systems/the-distro/nix-gerrit.git" + } + }, "nix2container": { "flake": false, "locked": { @@ -317,6 +337,7 @@ "hydra", "nix" ], + "nix-gerrit": "nix-gerrit", "nixpkgs": "nixpkgs", "terranix": "terranix" } diff --git a/flake.nix b/flake.nix index c3abfa6..7086851 100644 --- a/flake.nix +++ b/flake.nix @@ -14,6 +14,9 @@ hydra.url = "git+https://git.lix.systems/lix-project/hydra.git"; hydra.inputs.nixpkgs.follows = "nixpkgs"; + nix-gerrit.url = "git+https://git.lix.systems/the-distro/nix-gerrit.git"; + nix-gerrit.inputs.nixpkgs.follows = "nixpkgs"; + lix.follows = "hydra/nix"; }; @@ -25,6 +28,7 @@ overlays = [ inputs.hydra.overlays.default inputs.lix.overlays.default + inputs.nix-gerrit.overlays.default ]; }; lib = pkgs.lib; @@ -69,6 +73,7 @@ overlays = [ inputs.hydra.overlays.default inputs.lix.overlays.default + inputs.nix-gerrit.overlays.default ]; }; meta.specialArgs.inputs = inputs; diff --git a/overlays/default.nix b/overlays/default.nix index 1ccdeda..fe51488 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -1,3 +1 @@ -[ - (import ./gerrit.nix) -] +[] diff --git a/overlays/gerrit.nix b/overlays/gerrit.nix deleted file mode 100644 index f38e445..0000000 --- a/overlays/gerrit.nix +++ /dev/null @@ -1,9 +0,0 @@ -self: super: { - buildBazelPackageNG = self.callPackage ../pkgs/buildBazelPackageNG { }; - gerrit = self.callPackage ../pkgs/gerrit { }; - buildGerritBazelPlugin = self.callPackage ../pkgs/gerrit_plugins/builder.nix { }; - gerritPlugins = { - code-owners = self.callPackage ../pkgs/gerrit_plugins/code-owners { }; - oauth = self.callPackage ../pkgs/gerrit_plugins/oauth { }; - }; -} diff --git a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/default.nix b/pkgs/buildBazelPackageNG/bazelRulesJavaHook/default.nix deleted file mode 100644 index eb8332e..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/default.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ makeSetupHook }: - -makeSetupHook { - name = "rules_java_bazel_hook"; - substitutions = { - local_java = ./local_java; - }; -} ./setup-hook.sh diff --git a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/BUILD.bazel b/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/BUILD.bazel deleted file mode 100644 index 8bea495..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/BUILD.bazel +++ /dev/null @@ -1,3 +0,0 @@ -alias(name = "jdk", actual = "@local_jdk//:jdk") -alias(name = "toolchain", actual = "@local_jdk//:toolchain") -alias(name = "bootstrap_runtime_toolchain", actual = "@local_jdk//:bootstrap_runtime_toolchain") diff --git a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/WORKSPACE b/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/WORKSPACE deleted file mode 100644 index 5b31078..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/local_java/WORKSPACE +++ /dev/null @@ -1 +0,0 @@ -workspace(name = "local_java") diff --git a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/setup-hook.sh b/pkgs/buildBazelPackageNG/bazelRulesJavaHook/setup-hook.sh deleted file mode 100644 index f7f7e3a..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesJavaHook/setup-hook.sh +++ /dev/null @@ -1,17 +0,0 @@ -prePatchHooks+=(_setupLocalJavaRepo) - -javaVersions=(11 17 21) -javaPlatforms=( - "linux" "linux_aarch64" "linux_ppc64le" "linux_s390x" - "macos" "macos_aarch64" - "win" "win_arm64") - -_setupLocalJavaRepo() { - for javaVersion in ${javaVersions[@]}; do - for javaPlatform in ${javaPlatforms[@]}; do - bazelFlagsArray+=( - "--override_repository=remotejdk${javaVersion}_${javaPlatform}=@local_java@" - ) - done - done -} diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/default.nix b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/default.nix deleted file mode 100644 index c99cc39..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/default.nix +++ /dev/null @@ -1,53 +0,0 @@ -{ stdenvNoCC -, lib -, makeSetupHook -, fetchFromGitHub -, coreutils -, gnugrep -, nodejs -, yarn -, git -, cacert -}: -let - rulesNodeJS = stdenvNoCC.mkDerivation rec { - pname = "bazelbuild-rules_nodejs"; - version = "5.8.5"; - - src = fetchFromGitHub { - owner = "bazelbuild"; - repo = "rules_nodejs"; - rev = version; - hash = "sha256-6UbYRrOnS93+pK4VI016gQZv2jLCzkJn6wJ4vZNCNjY="; - }; - - dontBuild = true; - - postPatch = '' - shopt -s globstar - for i in **/*.bzl **/*.sh **/*.cjs; do - substituteInPlace "$i" \ - --replace-quiet '#!/usr/bin/env bash' '#!${stdenvNoCC.shell}' \ - --replace-quiet '#!/bin/bash' '#!${stdenvNoCC.shell}' - done - sed -i '/^#!/a export PATH=${lib.makeBinPath [ coreutils gnugrep ]}:$PATH' internal/node/launcher.sh - ''; - - installPhase = '' - cp -R . $out - ''; - }; -in makeSetupHook { - name = "bazelbuild-rules_nodejs-5-hook"; - propagatedBuildInputs = [ - nodejs - yarn - git - cacert - ]; - substitutions = { - inherit nodejs yarn cacert rulesNodeJS; - local_node = ./local_node; - local_yarn = ./local_yarn; - }; -} ./setup-hook.sh diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/BUILD b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/BUILD deleted file mode 100644 index d764d23..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/BUILD +++ /dev/null @@ -1,20 +0,0 @@ -load("@build_bazel_rules_nodejs//nodejs:toolchain.bzl", _node_toolchain = "node_toolchain") - -package(default_visibility = ["//visibility:public"]) - -exports_files([ - "bin/node", - "bin/npm", -]) - -_node_toolchain( - name = "node_toolchain", - target_tool_path = "__NODEJS__/bin/node", - npm_path = "__NODEJS__/bin/npm", -) - -toolchain( - name = "nodejs", - toolchain = ":node_toolchain", - toolchain_type = "@build_bazel_rules_nodejs//nodejs:toolchain_type", -) diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/WORKSPACE b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/WORKSPACE deleted file mode 100644 index 5bc1698..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/WORKSPACE +++ /dev/null @@ -1 +0,0 @@ -workspace(name = "nodejs") diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/node b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/node deleted file mode 100644 index ef1f010..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/node +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec "__NODEJS__/bin/node" "$@" diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/npm b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/npm deleted file mode 100644 index 63a985d..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_node/bin/npm +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -exec "__NODEJS__/bin/npm" "$@" diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/BUILD b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/BUILD deleted file mode 100644 index e69de29..0000000 diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/WORKSPACE b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/WORKSPACE deleted file mode 100644 index 2a1b7d4..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/WORKSPACE +++ /dev/null @@ -1 +0,0 @@ -workspace(name = "yarn") diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/bin/yarn b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/bin/yarn deleted file mode 100644 index 2009572..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/local_yarn/bin/yarn +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec "__YARN__/bin/yarn" "$@" diff --git a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/setup-hook.sh b/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/setup-hook.sh deleted file mode 100644 index 5e3cf1e..0000000 --- a/pkgs/buildBazelPackageNG/bazelRulesNodeJS5Hook/setup-hook.sh +++ /dev/null @@ -1,63 +0,0 @@ -prePatchHooks+=(_setupLocalNodeRepos) -preBuildHooks+=(_setupYarnCache) - -case "$bazelPhase" in - cache) - postInstallHooks+=(_copyYarnCache) - ;; - build) - preBuildHooks+=(_linkYarnCache) - ;; - *) - echo "Unexpected bazelPhase '$bazelPhase' (want cache or build)" >&2 - exit 1 - ;; -esac - - -_setupLocalNodeRepos() { - cp -R @local_node@ $HOME/local_node - chmod -R +w $HOME/local_node - substituteInPlace $HOME/local_node/bin/node \ - --replace-fail '__NODEJS__' '@nodejs@' - substituteInPlace $HOME/local_node/bin/npm \ - --replace-fail '__NODEJS__' '@nodejs@' - substituteInPlace $HOME/local_node/BUILD \ - --replace-fail '__NODEJS__' '@nodejs@' - chmod -R +x $HOME/local_node/bin/* - - cp -R @local_yarn@ $HOME/local_yarn - chmod -R +w $HOME/local_yarn - substituteInPlace $HOME/local_yarn/bin/yarn \ - --replace-fail '__YARN__' '@yarn@' - chmod -R +x $HOME/local_yarn/bin/* - - bazelFlagsArray+=( - "--override_repository=build_bazel_rules_nodejs=@rulesNodeJS@" - - "--override_repository=nodejs_linux_amd64=$HOME/local_node" - "--override_repository=nodejs_linux_arm64=$HOME/local_node" - "--override_repository=nodejs_linux_s390x=$HOME/local_node" - "--override_repository=nodejs_linux_ppc64le=$HOME/local_node" - "--override_repository=nodejs_darwin_amd64=$HOME/local_node" - "--override_repository=nodejs_darwin_arm64=$HOME/local_node" - "--override_repository=nodejs_windows_amd64=$HOME/local_node" - "--override_repository=nodejs_windows_arm64=$HOME/local_node" - "--override_repository=nodejs=$HOME/local_node" - - "--override_repository=yarn=$HOME/local_yarn" - ) -} - -_setupYarnCache() { - @yarn@/bin/yarn config set cafile "@cacert@/etc/ssl/certs/ca-bundle.crt" - @yarn@/bin/yarn config set yarn-offline-mirror "$HOME/yarn-offline-mirror" -} - -_copyYarnCache() { - cp -R "$HOME/yarn-offline-mirror" "$out/yarn-offline-mirror" -} - -_linkYarnCache() { - ln -sf "$cache/yarn-offline-mirror" "$HOME/yarn-offline-mirror" -} diff --git a/pkgs/buildBazelPackageNG/default.nix b/pkgs/buildBazelPackageNG/default.nix deleted file mode 100644 index b131b95..0000000 --- a/pkgs/buildBazelPackageNG/default.nix +++ /dev/null @@ -1,115 +0,0 @@ -{ stdenv -, lib -, pkgs -, coreutils -}: - -let - hooks = { - bazelRulesJavaHook = pkgs.callPackage ./bazelRulesJavaHook { }; - bazelRulesNodeJS5Hook = pkgs.callPackage ./bazelRulesNodeJS5Hook { }; - }; - - builder = { - name ? "${baseAttrs.pname}-${baseAttrs.version}" - , bazelTargets - , bazel ? pkgs.bazel - , depsHash - , extraCacheInstall ? "" - , extraBuildSetup ? "" - , extraBuildInstall ? "" - , ... - }@baseAttrs: - - let - cleanAttrs = lib.flip removeAttrs [ - "bazelTargets" "depsHash" "extraCacheInstall" "extraBuildSetup" "extraBuildInstall" - ]; - attrs = cleanAttrs baseAttrs; - - base = stdenv.mkDerivation (attrs // { - nativeBuildInputs = (attrs.nativeBuildInputs or []) ++ [ - bazel - ]; - - preUnpack = '' - if [[ ! -d $HOME ]]; then - export HOME=$NIX_BUILD_TOP/home - mkdir -p $HOME - fi - ''; - - bazelTargetNames = builtins.attrNames bazelTargets; - }); - - cache = base.overrideAttrs (base: { - name = "${name}-deps"; - - bazelPhase = "cache"; - - buildPhase = '' - runHook preBuild - - bazel sync --repository_cache=repository-cache $bazelFlags "''${bazelFlagsArray[@]}" - bazel build --repository_cache=repository-cache --nobuild $bazelFlags "''${bazelFlagsArray[@]}" $bazelTargetNames - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - mkdir $out - echo "${bazel.version}" > $out/bazel_version - cp -R repository-cache $out/repository-cache - ${extraCacheInstall} - - runHook postInstall - ''; - - outputHashMode = "recursive"; - outputHash = depsHash; - }); - - build = base.overrideAttrs (base: { - bazelPhase = "build"; - - inherit cache; - - nativeBuildInputs = (base.nativeBuildInputs or []) ++ [ - coreutils - ]; - - buildPhase = '' - runHook preBuild - - ${extraBuildSetup} - bazel build --repository_cache=$cache/repository-cache $bazelFlags "''${bazelFlagsArray[@]}" $bazelTargetNames - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - ${builtins.concatStringsSep "\n" (lib.mapAttrsToList (target: outPath: lib.optionalString (outPath != null) '' - TARGET_OUTPUTS="$(bazel cquery --repository_cache=$cache/repository-cache $bazelFlags "''${bazelFlagsArray[@]}" --output=files "${target}")" - if [[ "$(echo "$TARGET_OUTPUTS" | wc -l)" -gt 1 ]]; then - echo "Installing ${target}'s outputs ($TARGET_OUTPUTS) into ${outPath} as a directory" - mkdir -p "${outPath}" - cp $TARGET_OUTPUTS "${outPath}" - else - echo "Installing ${target}'s output ($TARGET_OUTPUTS) to ${outPath}" - mkdir -p "${dirOf outPath}" - cp "$TARGET_OUTPUTS" "${outPath}" - fi - '') bazelTargets)} - ${extraBuildInstall} - - runHook postInstall - ''; - }); - in build; -in hooks // { - __functor = self: lib.makeOverridable builder; -} diff --git a/pkgs/gerrit/0001-Syntax-highlight-nix.patch b/pkgs/gerrit/0001-Syntax-highlight-nix.patch deleted file mode 100644 index d17dc27..0000000 --- a/pkgs/gerrit/0001-Syntax-highlight-nix.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 216843cff4a8e41ad9887118751a412c1a22ce72 Mon Sep 17 00:00:00 2001 -From: Luke Granger-Brown -Date: Thu, 2 Jul 2020 23:02:32 +0100 -Subject: [PATCH 1/3] Syntax highlight nix - ---- - .../app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts | 1 + - resources/com/google/gerrit/server/mime/mime-types.properties | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -index 50742903de..d1e89920cc 100644 ---- a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -+++ b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -@@ -98,6 +98,7 @@ const LANGUAGE_MAP = new Map([ - ['text/x-vhdl', 'vhdl'], - ['text/x-yaml', 'yaml'], - ['text/vbscript', 'vbscript'], -+ ['text/x-nix', 'nix'], - ]); - - const CLASS_PREFIX = 'gr-syntax gr-syntax-'; -diff --git a/resources/com/google/gerrit/server/mime/mime-types.properties b/resources/com/google/gerrit/server/mime/mime-types.properties -index 642ef474a5..97f1ff835b 100644 ---- a/resources/com/google/gerrit/server/mime/mime-types.properties -+++ b/resources/com/google/gerrit/server/mime/mime-types.properties -@@ -154,6 +154,7 @@ msgenny = text/x-msgenny - mts = application/typescript - nb = text/x-mathematica - nginx.conf = text/x-nginx-conf -+nix = text/x-nix - nsh = text/x-nsis - nsi = text/x-nsis - nt = text/n-triples --- -2.45.1 - diff --git a/pkgs/gerrit/0002-Syntax-highlight-rules.pl.patch b/pkgs/gerrit/0002-Syntax-highlight-rules.pl.patch deleted file mode 100644 index d0da61d..0000000 --- a/pkgs/gerrit/0002-Syntax-highlight-rules.pl.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 63f1ff6ea749ae2af29a53463bca81bc3f4bf25b Mon Sep 17 00:00:00 2001 -From: Luke Granger-Brown -Date: Thu, 2 Jul 2020 23:02:43 +0100 -Subject: [PATCH 2/3] Syntax highlight rules.pl - ---- - .../app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts | 1 + - resources/com/google/gerrit/server/mime/mime-types.properties | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -index d1e89920cc..5d62af1c64 100644 ---- a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -+++ b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts -@@ -72,6 +72,7 @@ const LANGUAGE_MAP = new Map([ - ['text/x-perl', 'perl'], - ['text/x-pgsql', 'pgsql'], // postgresql - ['text/x-php', 'php'], -+ ['text/x-prolog', 'prolog'], - ['text/x-properties', 'properties'], - ['text/x-protobuf', 'protobuf'], - ['text/x-puppet', 'puppet'], -diff --git a/resources/com/google/gerrit/server/mime/mime-types.properties b/resources/com/google/gerrit/server/mime/mime-types.properties -index 97f1ff835b..85d630340f 100644 ---- a/resources/com/google/gerrit/server/mime/mime-types.properties -+++ b/resources/com/google/gerrit/server/mime/mime-types.properties -@@ -208,6 +208,7 @@ rq = application/sparql-query - rs = text/x-rustsrc - rss = application/xml - rst = text/x-rst -+rules.pl = text/x-prolog - README.md = text/x-gfm - s = text/x-gas - sas = text/x-sas --- -2.45.1 - diff --git a/pkgs/gerrit/0003-Add-titles-to-CLs-over-HTTP.patch b/pkgs/gerrit/0003-Add-titles-to-CLs-over-HTTP.patch deleted file mode 100644 index a5881e5..0000000 --- a/pkgs/gerrit/0003-Add-titles-to-CLs-over-HTTP.patch +++ /dev/null @@ -1,214 +0,0 @@ -From ca2df6d7f53441d443d42908e30bf60fbfc15392 Mon Sep 17 00:00:00 2001 -From: Luke Granger-Brown -Date: Thu, 2 Jul 2020 23:03:02 +0100 -Subject: [PATCH 3/3] Add titles to CLs over HTTP - ---- - .../gerrit/httpd/raw/IndexHtmlUtil.java | 12 +++- - .../google/gerrit/httpd/raw/IndexServlet.java | 8 ++- - .../google/gerrit/httpd/raw/StaticModule.java | 5 +- - .../gerrit/httpd/raw/TitleComputer.java | 67 +++++++++++++++++++ - .../gerrit/httpd/raw/PolyGerritIndexHtml.soy | 4 +- - 5 files changed, 88 insertions(+), 8 deletions(-) - create mode 100644 java/com/google/gerrit/httpd/raw/TitleComputer.java - -diff --git a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java -index a92dd18f04..f87c46d321 100644 ---- a/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java -+++ b/java/com/google/gerrit/httpd/raw/IndexHtmlUtil.java -@@ -41,6 +41,7 @@ import java.util.Collections; - import java.util.HashMap; - import java.util.HashSet; - import java.util.Map; -+import java.util.Optional; - import java.util.Set; - import java.util.function.Function; - -@@ -63,13 +64,14 @@ public class IndexHtmlUtil { - String faviconPath, - Map urlParameterMap, - Function urlInScriptTagOrdainer, -- String requestedURL) -+ String requestedURL, -+ TitleComputer titleComputer) - throws URISyntaxException, RestApiException { - ImmutableMap.Builder data = ImmutableMap.builder(); - data.putAll( - staticTemplateData( - canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer)) -- .putAll(dynamicTemplateData(gerritApi, requestedURL, canonicalURL)); -+ .putAll(dynamicTemplateData(gerritApi, requestedURL, canonicalURL, titleComputer)); - Set enabledExperiments = new HashSet<>(); - enabledExperiments.addAll(experimentFeatures.getEnabledExperimentFeatures()); - // Add all experiments enabled through url -@@ -82,7 +84,7 @@ public class IndexHtmlUtil { - - /** Returns dynamic parameters of {@code index.html}. */ - public static ImmutableMap dynamicTemplateData( -- GerritApi gerritApi, String requestedURL, String canonicalURL) -+ GerritApi gerritApi, String requestedURL, String canonicalURL, TitleComputer titleComputer) - throws RestApiException, URISyntaxException { - ImmutableMap.Builder data = ImmutableMap.builder(); - Map initialData = new HashMap<>(); -@@ -141,6 +143,10 @@ public class IndexHtmlUtil { - } - - data.put("gerritInitialData", initialData); -+ -+ Optional title = titleComputer.computeTitle(requestedURL); -+ title.ifPresent(s -> data.put("title", s)); -+ - return data.build(); - } - -diff --git a/java/com/google/gerrit/httpd/raw/IndexServlet.java b/java/com/google/gerrit/httpd/raw/IndexServlet.java -index fcb821e5ae..e1464b992b 100644 ---- a/java/com/google/gerrit/httpd/raw/IndexServlet.java -+++ b/java/com/google/gerrit/httpd/raw/IndexServlet.java -@@ -48,13 +48,15 @@ public class IndexServlet extends HttpServlet { - private final ExperimentFeatures experimentFeatures; - private final SoySauce soySauce; - private final Function urlOrdainer; -+ private TitleComputer titleComputer; - - IndexServlet( - @Nullable String canonicalUrl, - @Nullable String cdnPath, - @Nullable String faviconPath, - GerritApi gerritApi, -- ExperimentFeatures experimentFeatures) { -+ ExperimentFeatures experimentFeatures, -+ TitleComputer titleComputer) { - this.canonicalUrl = canonicalUrl; - this.cdnPath = cdnPath; - this.faviconPath = faviconPath; -@@ -69,6 +71,7 @@ public class IndexServlet extends HttpServlet { - (s) -> - UnsafeSanitizedContentOrdainer.ordainAsSafe( - s, SanitizedContent.ContentKind.TRUSTED_RESOURCE_URI); -+ this.titleComputer = titleComputer; - } - - @Override -@@ -86,7 +89,8 @@ public class IndexServlet extends HttpServlet { - faviconPath, - parameterMap, - urlOrdainer, -- getRequestUrl(req)); -+ getRequestUrl(req), -+ titleComputer); - renderer = soySauce.renderTemplate("com.google.gerrit.httpd.raw.Index").setData(templateData); - } catch (URISyntaxException | RestApiException e) { - throw new IOException(e); -diff --git a/java/com/google/gerrit/httpd/raw/StaticModule.java b/java/com/google/gerrit/httpd/raw/StaticModule.java -index b00294f73e..f1c1aae12c 100644 ---- a/java/com/google/gerrit/httpd/raw/StaticModule.java -+++ b/java/com/google/gerrit/httpd/raw/StaticModule.java -@@ -224,10 +224,11 @@ public class StaticModule extends ServletModule { - @CanonicalWebUrl @Nullable String canonicalUrl, - @GerritServerConfig Config cfg, - GerritApi gerritApi, -- ExperimentFeatures experimentFeatures) { -+ ExperimentFeatures experimentFeatures, -+ TitleComputer titleComputer) { - String cdnPath = options.devCdn().orElseGet(() -> cfg.getString("gerrit", null, "cdnPath")); - String faviconPath = cfg.getString("gerrit", null, "faviconPath"); -- return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, experimentFeatures); -+ return new IndexServlet(canonicalUrl, cdnPath, faviconPath, gerritApi, experimentFeatures, titleComputer); - } - - @Provides -diff --git a/java/com/google/gerrit/httpd/raw/TitleComputer.java b/java/com/google/gerrit/httpd/raw/TitleComputer.java -new file mode 100644 -index 0000000000..8fd2053ad0 ---- /dev/null -+++ b/java/com/google/gerrit/httpd/raw/TitleComputer.java -@@ -0,0 +1,67 @@ -+package com.google.gerrit.httpd.raw; -+ -+import com.google.common.flogger.FluentLogger; -+import com.google.gerrit.entities.Change; -+import com.google.gerrit.extensions.restapi.ResourceConflictException; -+import com.google.gerrit.extensions.restapi.ResourceNotFoundException; -+import com.google.gerrit.server.change.ChangeResource; -+import com.google.gerrit.server.permissions.PermissionBackendException; -+import com.google.gerrit.server.restapi.change.ChangesCollection; -+import com.google.inject.Inject; -+import com.google.inject.Provider; -+import com.google.inject.Singleton; -+ -+import java.net.MalformedURLException; -+import java.net.URL; -+import java.util.Optional; -+import java.util.regex.Matcher; -+import java.util.regex.Pattern; -+ -+@Singleton -+public class TitleComputer { -+ private static final FluentLogger logger = FluentLogger.forEnclosingClass(); -+ -+ @Inject -+ public TitleComputer(Provider changes) { -+ this.changes = changes; -+ } -+ -+ public Optional computeTitle(String requestedURI) { -+ URL url = null; -+ try { -+ url = new URL(requestedURI); -+ } catch (MalformedURLException e) { -+ logger.atWarning().log("Failed to turn %s into a URL.", requestedURI); -+ return Optional.empty(); -+ } -+ -+ // Try to turn this into a change. -+ Optional changeId = tryExtractChange(url.getPath()); -+ if (changeId.isPresent()) { -+ return titleFromChangeId(changeId.get()); -+ } -+ -+ return Optional.empty(); -+ } -+ -+ private static final Pattern extractChangeIdRegex = Pattern.compile("^/(?:c/.*/\\+/)?(?[0-9]+)(?:/[0-9]+)?(?:/.*)?$"); -+ private final Provider changes; -+ -+ private Optional tryExtractChange(String path) { -+ Matcher m = extractChangeIdRegex.matcher(path); -+ if (!m.matches()) { -+ return Optional.empty(); -+ } -+ return Change.Id.tryParse(m.group("changeId")); -+ } -+ -+ private Optional titleFromChangeId(Change.Id changeId) { -+ ChangesCollection changesCollection = changes.get(); -+ try { -+ ChangeResource changeResource = changesCollection.parse(changeId); -+ return Optional.of(changeResource.getChange().getSubject()); -+ } catch (ResourceConflictException | ResourceNotFoundException | PermissionBackendException e) { -+ return Optional.empty(); -+ } -+ } -+} -diff --git a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy -index 5ff1822cd9..81c3cdf0e1 100644 ---- a/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy -+++ b/resources/com/google/gerrit/httpd/raw/PolyGerritIndexHtml.soy -@@ -33,10 +33,12 @@ - {@param? defaultDashboardHex: ?} - {@param? dashboardQuery: ?} - {@param? userIsAuthenticated: ?} -+ {@param? title: ?} - {\n} - {\n} - {\n} -- {\n} -+ {if $title}{$title} · Gerrit Code Review{\n}{/if} -+ {\n} - {\n} - {\n} - --- -2.45.1 - diff --git a/pkgs/gerrit/bazelrc b/pkgs/gerrit/bazelrc deleted file mode 100644 index f77da77..0000000 --- a/pkgs/gerrit/bazelrc +++ /dev/null @@ -1,11 +0,0 @@ -# Not using common --repository_cache because Gerrit's bazelrc overrides this... -build --repository_cache=repository-cache -build --action_env=SSL_CERT_FILE -build --action_env=GERRIT_CACHE_HOME -build --tool_java_runtime_version=local_jdk --java_runtime_version=local_jdk -build --workspace_status_command="cat .version" - -# Disable errorprone -build --javacopt="-XepDisableAllChecks" - -sync --repository_cache=repository-cache diff --git a/pkgs/gerrit/default.nix b/pkgs/gerrit/default.nix deleted file mode 100644 index 270dbe5..0000000 --- a/pkgs/gerrit/default.nix +++ /dev/null @@ -1,111 +0,0 @@ -{ buildBazelPackageNG -, lib -, fetchgit -, bazel_7 -, python3 -, openjdk21_headless -, curl -, unzip -, extraBazelPackageAttrs ? {} -}: - -let - inherit (buildBazelPackageNG) bazelRulesJavaHook bazelRulesNodeJS5Hook; -in -(buildBazelPackageNG rec { - pname = "gerrit"; - version = "3.10.0"; - - bazel = bazel_7; - - src = (fetchgit { - url = "https://gerrit.googlesource.com/gerrit"; - rev = "v${version}"; - fetchSubmodules = true; - deepClone = true; - hash = "sha256-FpKuzityHuHNYBIOL8YUjCLlkuVBfxjvHECb26NsZNE="; - }).overrideAttrs (_: { - env.NIX_PREFETCH_GIT_CHECKOUT_HOOK = '' - pushd "$dir" >/dev/null - ${python3}/bin/python tools/workspace_status_release.py | sort > .version - popd >/dev/null - - # delete all the .git; we can't do this using fetchgit if deepClone is on, - # but our mischief has already been achieved by the python command above :) - find "$dir" -name .git -print0 | xargs -0 rm -rf - ''; - }); - depsHash = "sha256-OS2kLXjtuWf+XRyQO2qGvEaAOvxqu20+gXR+fsCvpMc="; - - patches = [ - ./0001-Syntax-highlight-nix.patch - ./0002-Syntax-highlight-rules.pl.patch - ./0003-Add-titles-to-CLs-over-HTTP.patch - ]; - - nativeBuildInputs = [ - bazelRulesJavaHook - bazelRulesNodeJS5Hook - - curl - openjdk21_headless - python3 - unzip - ]; - - prePatch = '' - rm .bazelversion - - ln -sf ${./bazelrc} user.bazelrc - - ln -sf ${./workspace_overrides.bzl} workspace_overrides.bzl - substituteInPlace WORKSPACE \ - --replace-fail 'load("@io_bazel_rules_webtesting//web:repositories.bzl"' 'load("//:workspace_overrides.bzl"' \ - --replace-fail 'load("@io_bazel_rules_webtesting//web/versioned:browsers-0.3.3.bzl"' 'load("//:workspace_overrides.bzl"' - - patchShebangs Documentation/replace_macros.py - ''; - - postPatch = '' - sed -Ei 's,^(STABLE_BUILD_GERRIT_LABEL.*)$,\1-dirty-nix,' .version - ''; - - preBuild = '' - export GERRIT_CACHE_HOME=$HOME/gerrit-cache - ''; - - extraCacheInstall = '' - cp -R $GERRIT_CACHE_HOME $out/gerrit-cache - ''; - - extraBuildSetup = '' - ln -sf $cache/gerrit-cache $GERRIT_CACHE_HOME - ''; - extraBuildInstall = '' - mkdir -p "$out"/share/api/ - unzip bazel-bin/api-skip-javadoc.zip -d "$out"/share/api - ''; - - bazelTargets = { - "//:release" = "$out/webapps/gerrit-${version}.war"; - "//:api-skip-javadoc" = null; - }; - - passthru = { - # A list of plugins that are part of the gerrit.war file. - # Use `java -jar gerrit.war ls | grep -Po '(?<=plugins/)[^.]+' | sed -e 's,^,",' -e 's,$,",' | sort` to generate that list. - plugins = [ - "codemirror-editor" - "commit-message-length-validator" - "delete-project" - "download-commands" - "gitiles" - "hooks" - "plugin-manager" - "replication" - "reviewnotes" - "singleusergroup" - "webhooks" - ]; - }; -}).override extraBazelPackageAttrs diff --git a/pkgs/gerrit/detzip.go b/pkgs/gerrit/detzip.go deleted file mode 100644 index 511c18e..0000000 --- a/pkgs/gerrit/detzip.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -import ( - "archive/zip" - "flag" - "fmt" - "io" - "log" - "os" - "path/filepath" - "sort" - "strings" -) - -var ( - exclude = flag.String("exclude", "", "comma-separated list of filenames to exclude (in any directory)") -) - -func init() { - flag.Usage = func() { - fmt.Fprintf(flag.CommandLine.Output(), "Usage of %s [zip file] [directory]:\n", os.Args[0]) - flag.PrintDefaults() - } -} - -func listToMap(ss []string) map[string]bool { - m := make(map[string]bool) - for _, s := range ss { - m[s] = true - } - return m -} - -func main() { - flag.Parse() - if flag.NArg() != 2 { - flag.Usage() - os.Exit(1) - } - - outPath := flag.Arg(0) - dirPath := flag.Arg(1) - - excludeFiles := listToMap(strings.Split(*exclude, ",")) - - // Aggregate all files first. - var files []string - filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if info.IsDir() { - return nil - } - if excludeFiles[info.Name()] { - return nil - } - files = append(files, path) - return nil - }) - - // Create zip - outW, err := os.Create(outPath) - if err != nil { - log.Fatalf("Create(%q): %v", outPath, err) - } - - zipW := zip.NewWriter(outW) - - // Output files in alphabetical order - sort.Strings(files) - for _, f := range files { - fw, err := zipW.CreateHeader(&zip.FileHeader{ - Name: f, - Method: zip.Store, - }) - if err != nil { - log.Fatalf("creating %q in zip: %v", f, err) - } - - ff, err := os.Open(f) - if err != nil { - log.Fatalf("opening %q: %v", f, err) - } - if _, err := io.Copy(fw, ff); err != nil { - log.Fatalf("copying %q to zip: %v", f, err) - } - ff.Close() - } - - if err := zipW.Close(); err != nil { - log.Fatalf("writing ZIP central directory: %v", err) - } - if err := outW.Close(); err != nil { - log.Fatalf("closing ZIP file: %v", err) - } -} diff --git a/pkgs/gerrit/workspace_overrides.bzl b/pkgs/gerrit/workspace_overrides.bzl deleted file mode 100644 index 8393686..0000000 --- a/pkgs/gerrit/workspace_overrides.bzl +++ /dev/null @@ -1,5 +0,0 @@ -def web_test_repositories(): - pass - -def browser_repositories(*args, **kwargs): - pass diff --git a/pkgs/gerrit_plugins/builder.nix b/pkgs/gerrit_plugins/builder.nix deleted file mode 100644 index a232625..0000000 --- a/pkgs/gerrit_plugins/builder.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ gerrit -, runCommandLocal -, lib -}: - -{ name -, version -, src -, depsHash ? null -, overlayPluginCmd ? '' - cp -R "${src}" "$out/plugins/${name}" - echo "STABLE_BUILD_${lib.toUpper name}_LABEL v${version}-nix${if patches != [] then "-dirty" else ""}" >> $out/.version - '' -, postOverlayPlugin ? "" -, postPatch ? "" -, patches ? [ ] -}: ((gerrit.override { - extraBazelPackageAttrs = (old: { - name = "${name}.jar"; - - src = runCommandLocal "${name}-src" { } '' - cp -R "${gerrit.src}" "$out" - chmod -R +w "$out" - ${overlayPluginCmd} - ${postOverlayPlugin} - ''; - depsHash = (if depsHash != null then depsHash else old.depsHash); - - bazelTargets = { - "//plugins/${name}" = "$out"; - }; - - extraBuildInstall = ""; - }); -}).overrideAttrs (super: { - postPatch = '' - ${super.postPatch or ""} - pushd "plugins/${name}" - ${lib.concatMapStringsSep "\n" (patch: '' - patch -p1 < ${patch} - '') patches} - popd - ${postPatch} - ''; -})) diff --git a/pkgs/gerrit_plugins/code-owners/default.nix b/pkgs/gerrit_plugins/code-owners/default.nix deleted file mode 100644 index 57a8ffb..0000000 --- a/pkgs/gerrit_plugins/code-owners/default.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ buildGerritBazelPlugin, fetchgit }: - -buildGerritBazelPlugin rec { - name = "code-owners"; - version = "7de40d8"; - src = fetchgit { - url = "https://gerrit.googlesource.com/plugins/code-owners"; - rev = "7de40d8b30e55eb64316b6fc3d0d00da9caddade"; - hash = "sha256-0sLwUcG9RN1o9vZGW8ErwL7UgJapgYoo8XMGsWLO25Q="; - }; - patches = [ - ./using-usernames.patch - ]; -} diff --git a/pkgs/gerrit_plugins/code-owners/using-usernames.patch b/pkgs/gerrit_plugins/code-owners/using-usernames.patch deleted file mode 100644 index 25079ae..0000000 --- a/pkgs/gerrit_plugins/code-owners/using-usernames.patch +++ /dev/null @@ -1,472 +0,0 @@ -commit 29ace6c38ac513f7ec56ca425230d5712c081043 -Author: Luke Granger-Brown -Date: Wed Sep 21 03:15:38 2022 +0100 - - Add support for usernames and groups - - Change-Id: I3ba8527f66216d08e555a6ac4451fe0d1e090de5 - -diff --git a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java -index 70009591..6dc596c9 100644 ---- a/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java -+++ b/java/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolver.java -@@ -17,6 +17,8 @@ package com.google.gerrit.plugins.codeowners.backend; - import static com.google.common.base.Preconditions.checkState; - import static com.google.common.collect.ImmutableMap.toImmutableMap; - import static com.google.common.collect.ImmutableSet.toImmutableSet; -+import static com.google.common.collect.ImmutableSetMultimap.flatteningToImmutableSetMultimap; -+import static com.google.common.collect.ImmutableSetMultimap.toImmutableSetMultimap; - import static com.google.gerrit.plugins.codeowners.backend.CodeOwnersInternalServerErrorException.newInternalServerError; - import static java.util.Objects.requireNonNull; - -@@ -25,6 +27,7 @@ import com.google.common.collect.ImmutableList; - import com.google.common.collect.ImmutableMap; - import com.google.common.collect.ImmutableMultimap; - import com.google.common.collect.ImmutableSet; -+import com.google.common.collect.ImmutableSetMultimap; - import com.google.common.collect.Iterables; - import com.google.common.collect.Streams; - import com.google.common.flogger.FluentLogger; -@@ -33,17 +36,24 @@ import com.google.gerrit.entities.Project; - import com.google.gerrit.metrics.Timer0; - import com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration; - import com.google.gerrit.plugins.codeowners.metrics.CodeOwnerMetrics; -+import com.google.gerrit.server.AnonymousUser; - import com.google.gerrit.server.CurrentUser; - import com.google.gerrit.server.IdentifiedUser; - import com.google.gerrit.server.account.AccountCache; - import com.google.gerrit.server.account.AccountControl; - import com.google.gerrit.server.account.AccountState; -+import com.google.gerrit.server.account.GroupBackend; -+import com.google.gerrit.server.account.GroupBackends; -+import com.google.gerrit.server.account.InternalGroupBackend; - import com.google.gerrit.server.account.externalids.ExternalId; - import com.google.gerrit.server.account.externalids.ExternalIdCache; - import com.google.gerrit.server.permissions.GlobalPermission; - import com.google.gerrit.server.permissions.PermissionBackend; - import com.google.gerrit.server.permissions.PermissionBackendException; -+import com.google.gerrit.server.util.RequestContext; -+import com.google.gerrit.server.util.ThreadLocalRequestContext; - import com.google.inject.Inject; -+import com.google.inject.OutOfScopeException; - import com.google.inject.Provider; - import java.io.IOException; - import java.nio.file.Path; -@@ -102,6 +112,8 @@ public class CodeOwnerResolver { - - @VisibleForTesting public static final String ALL_USERS_WILDCARD = "*"; - -+ public static final String GROUP_PREFIX = "group:"; -+ - private final CodeOwnersPluginConfiguration codeOwnersPluginConfiguration; - private final PermissionBackend permissionBackend; - private final Provider currentUser; -@@ -112,6 +124,8 @@ public class CodeOwnerResolver { - private final CodeOwnerMetrics codeOwnerMetrics; - private final UnresolvedImportFormatter unresolvedImportFormatter; - private final TransientCodeOwnerCache transientCodeOwnerCache; -+ private final InternalGroupBackend groupBackend; -+ private final ThreadLocalRequestContext context; - - // Enforce visibility by default. - private boolean enforceVisibility = true; -@@ -132,7 +146,9 @@ public class CodeOwnerResolver { - PathCodeOwners.Factory pathCodeOwnersFactory, - CodeOwnerMetrics codeOwnerMetrics, - UnresolvedImportFormatter unresolvedImportFormatter, -- TransientCodeOwnerCache transientCodeOwnerCache) { -+ TransientCodeOwnerCache transientCodeOwnerCache, -+ InternalGroupBackend groupBackend, -+ ThreadLocalRequestContext context) { - this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration; - this.permissionBackend = permissionBackend; - this.currentUser = currentUser; -@@ -143,6 +159,8 @@ public class CodeOwnerResolver { - this.codeOwnerMetrics = codeOwnerMetrics; - this.unresolvedImportFormatter = unresolvedImportFormatter; - this.transientCodeOwnerCache = transientCodeOwnerCache; -+ this.groupBackend = groupBackend; -+ this.context = context; - } - - /** -@@ -361,6 +379,12 @@ public class CodeOwnerResolver { - "cannot resolve code owner email %s: no account with this email exists", - CodeOwnerResolver.ALL_USERS_WILDCARD)); - } -+ if (codeOwnerReference.email().startsWith(GROUP_PREFIX)) { -+ return OptionalResultWithMessages.createEmpty( -+ String.format( -+ "cannot resolve code owner email %s: this is a group", -+ codeOwnerReference.email())); -+ } - - ImmutableList.Builder messageBuilder = ImmutableList.builder(); - AtomicBoolean ownedByAllUsers = new AtomicBoolean(false); -@@ -405,9 +429,53 @@ public class CodeOwnerResolver { - ImmutableMultimap annotations) { - requireNonNull(codeOwnerReferences, "codeOwnerReferences"); - -+ ImmutableSet groupsToResolve = -+ codeOwnerReferences.stream() -+ .map(CodeOwnerReference::email) -+ .filter(ref -> ref.startsWith(GROUP_PREFIX)) -+ .map(ref -> ref.substring(GROUP_PREFIX.length())) -+ .collect(toImmutableSet()); -+ -+ // When we call GroupBackends.findExactSuggestion we need to ensure that we -+ // have a user in context. This is because the suggestion backend is -+ // likely to want to try to check that we can actually see the group it's -+ // returning (which we also check for explicitly, because I have trust -+ // issues). -+ RequestContext oldCtx = context.getContext(); -+ // Check if we have a user in the context at all... -+ try { -+ oldCtx.getUser(); -+ } catch (OutOfScopeException | NullPointerException e) { -+ // Nope. -+ RequestContext newCtx = () -> { -+ return new AnonymousUser(); -+ }; -+ context.setContext(newCtx); -+ } -+ ImmutableSetMultimap resolvedGroups = null; -+ try { -+ resolvedGroups = -+ groupsToResolve.stream() -+ .map(groupName -> GroupBackends.findExactSuggestion(groupBackend, groupName)) -+ .filter(groupRef -> groupRef != null) -+ .filter(groupRef -> groupBackend.isVisibleToAll(groupRef.getUUID())) -+ .map(groupRef -> groupBackend.get(groupRef.getUUID())) -+ .collect(flatteningToImmutableSetMultimap( -+ groupRef -> GROUP_PREFIX + groupRef.getName(), -+ groupRef -> accountCache -+ .get(ImmutableSet.copyOf(groupRef.getMembers())) -+ .values().stream() -+ .map(accountState -> CodeOwner.create(accountState.account().id())))); -+ } finally { -+ context.setContext(oldCtx); -+ } -+ ImmutableSetMultimap usersToGroups = -+ resolvedGroups.inverse(); -+ - ImmutableSet emailsToResolve = - codeOwnerReferences.stream() - .map(CodeOwnerReference::email) -+ .filter(ref -> !ref.startsWith(GROUP_PREFIX)) - .filter(filterOutAllUsersWildCard(ownedByAllUsers)) - .collect(toImmutableSet()); - -@@ -442,7 +510,8 @@ public class CodeOwnerResolver { - ImmutableMap codeOwnersByEmail = - accountsByEmail.map(mapToCodeOwner()).collect(toImmutableMap(Pair::key, Pair::value)); - -- if (codeOwnersByEmail.keySet().size() < emailsToResolve.size()) { -+ if (codeOwnersByEmail.keySet().size() < emailsToResolve.size() || -+ resolvedGroups.keySet().size() < groupsToResolve.size()) { - hasUnresolvedCodeOwners.set(true); - } - -@@ -456,7 +525,9 @@ public class CodeOwnerResolver { - cachedCodeOwnersByEmail.entrySet().stream() - .filter(e -> e.getValue().isPresent()) - .map(e -> Pair.of(e.getKey(), e.getValue().get())); -- Streams.concat(newlyResolvedCodeOwnersStream, cachedCodeOwnersStream) -+ Stream> resolvedGroupsCodeOwnersStream = -+ resolvedGroups.entries().stream().map(e -> Pair.of(e.getKey(), e.getValue())); -+ Streams.concat(Streams.concat(newlyResolvedCodeOwnersStream, cachedCodeOwnersStream), resolvedGroupsCodeOwnersStream) - .forEach( - p -> { - ImmutableSet.Builder annotationBuilder = ImmutableSet.builder(); -@@ -467,6 +538,12 @@ public class CodeOwnerResolver { - annotationBuilder.addAll( - annotations.get(CodeOwnerReference.create(ALL_USERS_WILDCARD))); - -+ // annotations for the groups this user is in apply as well -+ for (String group : usersToGroups.get(p.value())) { -+ annotationBuilder.addAll( -+ annotations.get(CodeOwnerReference.create(group))); -+ } -+ - if (!codeOwnersWithAnnotations.containsKey(p.value())) { - codeOwnersWithAnnotations.put(p.value(), new HashSet<>()); - } -@@ -570,7 +647,7 @@ public class CodeOwnerResolver { - } - - messages.add(String.format("email %s has no domain", email)); -- return false; -+ return true; // TVL: we allow domain-less strings which are treated as usernames. - } - - /** -@@ -585,11 +662,29 @@ public class CodeOwnerResolver { - */ - private ImmutableMap> lookupExternalIds( - ImmutableList.Builder messages, ImmutableSet emails) { -+ String[] actualEmails = emails.stream() -+ .filter(email -> email.contains("@")) -+ .toArray(String[]::new); -+ ImmutableSet usernames = emails.stream() -+ .filter(email -> !email.contains("@")) -+ .collect(ImmutableSet.toImmutableSet()); - try { -- ImmutableMap> extIdsByEmail = -- externalIdCache.byEmails(emails.toArray(new String[0])).asMap(); -+ ImmutableMap> extIds = -+ new ImmutableMap.Builder>() -+ .putAll(externalIdCache.byEmails(actualEmails).asMap()) -+ .putAll(externalIdCache.allByAccount().entries().stream() -+ .map(entry -> entry.getValue()) -+ .filter(externalId -> -+ externalId.key().scheme() != null && -+ externalId.key().isScheme(ExternalId.SCHEME_USERNAME) && -+ usernames.contains(externalId.key().id())) -+ .collect(toImmutableSetMultimap( -+ externalId -> externalId.key().id(), -+ externalId -> externalId)) -+ .asMap()) -+ .build(); - emails.stream() -- .filter(email -> !extIdsByEmail.containsKey(email)) -+ .filter(email -> !extIds.containsKey(email)) - .forEach( - email -> { - transientCodeOwnerCache.cacheNonResolvable(email); -@@ -598,7 +693,7 @@ public class CodeOwnerResolver { - "cannot resolve code owner email %s: no account with this email exists", - email)); - }); -- return extIdsByEmail; -+ return extIds; - } catch (IOException e) { - throw newInternalServerError( - String.format("cannot resolve code owner emails: %s", emails), e); -@@ -815,6 +910,15 @@ public class CodeOwnerResolver { - user != null ? user.getLoggableName() : currentUser.get().getLoggableName())); - return true; - } -+ if (!email.contains("@")) { -+ // the email is the username of the account, or a group, or something else. -+ messages.add( -+ String.format( -+ "account %s is visible to user %s", -+ accountState.account().id(), -+ user != null ? user.getLoggableName() : currentUser.get().getLoggableName())); -+ return true; -+ } - - if (user != null) { - if (user.hasEmailAddress(email)) { -diff --git a/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParser.java b/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParser.java -index 5f350998..7977ba55 100644 ---- a/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParser.java -+++ b/java/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParser.java -@@ -149,7 +149,8 @@ public class FindOwnersCodeOwnerConfigParser implements CodeOwnerConfigParser { - private static final String EOL = "[\\s]*(#.*)?$"; // end-of-line - private static final String GLOB = "[^\\s,=]+"; // a file glob - -- private static final String EMAIL_OR_STAR = "([^\\s<>@,]+@[^\\s<>@#,]+|\\*)"; -+ // Also allows usernames, and group:$GROUP_NAME. -+ private static final String EMAIL_OR_STAR = "([^\\s<>@,]+@[^\\s<>@#,]+?|\\*|[a-zA-Z0-9_\\-]+|group:[a-zA-Z0-9_\\-]+)"; - private static final String EMAIL_LIST = - "(" + EMAIL_OR_STAR + "(" + COMMA + EMAIL_OR_STAR + ")*)"; - -diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackendTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackendTest.java -index 7ec92959..59cf7e05 100644 ---- a/javatests/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackendTest.java -+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/AbstractFileBasedCodeOwnerBackendTest.java -@@ -424,7 +424,7 @@ public abstract class AbstractFileBasedCodeOwnerBackendTest extends AbstractCode - .commit() - .parent(head) - .message("Add invalid test code owner config") -- .add(JgitPath.of(codeOwnerConfigKey.filePath(getFileName())).get(), "INVALID")); -+ .add(JgitPath.of(codeOwnerConfigKey.filePath(getFileName())).get(), "INVALID!")); - } - - // Try to update the code owner config. -diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolverTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolverTest.java -index 6171aca9..37699012 100644 ---- a/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolverTest.java -+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/CodeOwnerResolverTest.java -@@ -24,8 +24,10 @@ import com.google.gerrit.acceptance.TestAccount; - import com.google.gerrit.acceptance.TestMetricMaker; - import com.google.gerrit.acceptance.config.GerritConfig; - import com.google.gerrit.acceptance.testsuite.account.AccountOperations; -+import com.google.gerrit.acceptance.testsuite.group.GroupOperations; - import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations; - import com.google.gerrit.entities.Account; -+import com.google.gerrit.entities.AccountGroup; - import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest; - import com.google.gerrit.server.ServerInitiated; - import com.google.gerrit.server.account.AccountsUpdate; -@@ -51,6 +53,7 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest { - @Inject private RequestScopeOperations requestScopeOperations; - @Inject @ServerInitiated private Provider accountsUpdate; - @Inject private AccountOperations accountOperations; -+ @Inject private GroupOperations groupOperations; - @Inject private ExternalIdNotes.Factory externalIdNotesFactory; - @Inject private TestMetricMaker testMetricMaker; - @Inject private ExternalIdFactory externalIdFactory; -@@ -112,6 +115,18 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest { - .contains(String.format("account %s is visible to user %s", admin.id(), admin.username())); - } - -+ @Test -+ public void resolveCodeOwnerReferenceForUsername() throws Exception { -+ OptionalResultWithMessages result = -+ codeOwnerResolverProvider -+ .get() -+ .resolveWithMessages(CodeOwnerReference.create(admin.username())); -+ assertThat(result.get()).hasAccountIdThat().isEqualTo(admin.id()); -+ assertThat(result) -+ .hasMessagesThat() -+ .contains(String.format("account %s is visible to user %s", admin.id(), admin.username())); -+ } -+ - @Test - public void cannotResolveCodeOwnerReferenceForStarAsEmail() throws Exception { - OptionalResultWithMessages result = -@@ -127,6 +142,18 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest { - CodeOwnerResolver.ALL_USERS_WILDCARD)); - } - -+ @Test -+ public void cannotResolveCodeOwnerReferenceForGroup() throws Exception { -+ OptionalResultWithMessages result = -+ codeOwnerResolverProvider -+ .get() -+ .resolveWithMessages(CodeOwnerReference.create("group:Administrators")); -+ assertThat(result).isEmpty(); -+ assertThat(result) -+ .hasMessagesThat() -+ .contains("cannot resolve code owner email group:Administrators: this is a group"); -+ } -+ - @Test - public void resolveCodeOwnerReferenceForAmbiguousEmailIfOtherAccountIsInactive() - throws Exception { -@@ -397,6 +424,64 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest { - assertThat(result.hasUnresolvedCodeOwners()).isFalse(); - } - -+ @Test -+ public void resolvePathCodeOwnersWhenNonVisibleGroupIsUsed() throws Exception { -+ CodeOwnerConfig codeOwnerConfig = -+ CodeOwnerConfig.builder(CodeOwnerConfig.Key.create(project, "master", "/"), TEST_REVISION) -+ .addCodeOwnerSet( -+ CodeOwnerSet.createWithoutPathExpressions("group:Administrators")) -+ .build(); -+ -+ CodeOwnerResolverResult result = -+ codeOwnerResolverProvider -+ .get() -+ .resolvePathCodeOwners(codeOwnerConfig, Paths.get("/README.md")); -+ assertThat(result.codeOwnersAccountIds()).isEmpty(); -+ assertThat(result.ownedByAllUsers()).isFalse(); -+ assertThat(result.hasUnresolvedCodeOwners()).isTrue(); -+ } -+ -+ @Test -+ public void resolvePathCodeOwnersWhenVisibleGroupIsUsed() throws Exception { -+ AccountGroup.UUID createdGroupUUID = groupOperations -+ .newGroup() -+ .name("VisibleGroup") -+ .visibleToAll(true) -+ .addMember(admin.id()) -+ .create(); -+ -+ CodeOwnerConfig codeOwnerConfig = -+ CodeOwnerConfig.builder(CodeOwnerConfig.Key.create(project, "master", "/"), TEST_REVISION) -+ .addCodeOwnerSet( -+ CodeOwnerSet.createWithoutPathExpressions("group:VisibleGroup")) -+ .build(); -+ -+ CodeOwnerResolverResult result = -+ codeOwnerResolverProvider -+ .get() -+ .resolvePathCodeOwners(codeOwnerConfig, Paths.get("/README.md")); -+ assertThat(result.codeOwnersAccountIds()).containsExactly(admin.id()); -+ assertThat(result.ownedByAllUsers()).isFalse(); -+ assertThat(result.hasUnresolvedCodeOwners()).isFalse(); -+ } -+ -+ @Test -+ public void resolvePathCodeOwnersWhenUsernameIsUsed() throws Exception { -+ CodeOwnerConfig codeOwnerConfig = -+ CodeOwnerConfig.builder(CodeOwnerConfig.Key.create(project, "master", "/"), TEST_REVISION) -+ .addCodeOwnerSet( -+ CodeOwnerSet.createWithoutPathExpressions(admin.username())) -+ .build(); -+ -+ CodeOwnerResolverResult result = -+ codeOwnerResolverProvider -+ .get() -+ .resolvePathCodeOwners(codeOwnerConfig, Paths.get("/README.md")); -+ assertThat(result.codeOwnersAccountIds()).containsExactly(admin.id()); -+ assertThat(result.ownedByAllUsers()).isFalse(); -+ assertThat(result.hasUnresolvedCodeOwners()).isFalse(); -+ } -+ - @Test - public void resolvePathCodeOwnersNonResolvableCodeOwnersAreFilteredOut() throws Exception { - CodeOwnerConfig codeOwnerConfig = -@@ -655,7 +740,7 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest { - "domain example.com of email foo@example.org@example.com is allowed"); - assertIsEmailDomainAllowed( - "foo@example.org", false, "domain example.org of email foo@example.org is not allowed"); -- assertIsEmailDomainAllowed("foo", false, "email foo has no domain"); -+ assertIsEmailDomainAllowed("foo", true, "email foo has no domain"); - assertIsEmailDomainAllowed( - "foo@example.com@example.org", - false, -diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParserTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParserTest.java -index 260e635e..7aab99d0 100644 ---- a/javatests/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParserTest.java -+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/findowners/FindOwnersCodeOwnerConfigParserTest.java -@@ -158,16 +158,42 @@ public class FindOwnersCodeOwnerConfigParserTest extends AbstractCodeOwnerConfig - codeOwnerConfigParser.parse( - TEST_REVISION, - CodeOwnerConfig.Key.create(project, "master", "/"), -- getCodeOwnerConfig(EMAIL_1, "INVALID", "NOT_AN_EMAIL", EMAIL_2))); -+ getCodeOwnerConfig(EMAIL_1, "INVALID!", "NOT!AN_EMAIL", EMAIL_2))); - assertThat(exception.getFullMessage(FindOwnersBackend.CODE_OWNER_CONFIG_FILE_NAME)) - .isEqualTo( - String.format( - "invalid code owner config file '/OWNERS' (project = %s, branch = master):\n" -- + " invalid line: INVALID\n" -- + " invalid line: NOT_AN_EMAIL", -+ + " invalid line: INVALID!\n" -+ + " invalid line: NOT!AN_EMAIL", - project)); - } - -+ @Test -+ public void codeOwnerConfigWithUsernames() throws Exception { -+ assertParseAndFormat( -+ getCodeOwnerConfig(EMAIL_1, "USERNAME", EMAIL_2), -+ codeOwnerConfig -> -+ assertThat(codeOwnerConfig) -+ .hasCodeOwnerSetsThat() -+ .onlyElement() -+ .hasCodeOwnersEmailsThat() -+ .containsExactly(EMAIL_1, "USERNAME", EMAIL_2), -+ getCodeOwnerConfig(EMAIL_1, "USERNAME", EMAIL_2)); -+ } -+ -+ @Test -+ public void codeOwnerConfigWithGroups() throws Exception { -+ assertParseAndFormat( -+ getCodeOwnerConfig(EMAIL_1, "group:tvl-employees", EMAIL_2), -+ codeOwnerConfig -> -+ assertThat(codeOwnerConfig) -+ .hasCodeOwnerSetsThat() -+ .onlyElement() -+ .hasCodeOwnersEmailsThat() -+ .containsExactly(EMAIL_1, "group:tvl-employees", EMAIL_2), -+ getCodeOwnerConfig(EMAIL_1, "group:tvl-employees", EMAIL_2)); -+ } -+ - @Test - public void codeOwnerConfigWithComment() throws Exception { - assertParseAndFormat( diff --git a/pkgs/gerrit_plugins/oauth/default.nix b/pkgs/gerrit_plugins/oauth/default.nix deleted file mode 100644 index 00aefaa..0000000 --- a/pkgs/gerrit_plugins/oauth/default.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ buildGerritBazelPlugin, fetchgit }: - -buildGerritBazelPlugin rec { - name = "oauth"; - version = "982316"; - src = fetchgit { - url = "https://gerrit.googlesource.com/plugins/oauth"; - rev = "98231604d60788bb43490f1a301d792817ac8008"; - hash = "sha256-AuVO1Yys8BYqGHZI/adszCUg0JM2v4Td4fe26LdOPLM="; - }; - depsHash = "sha256-7SC4NXm4zGeJrYBqtEvcrLmsZmXEX8P21J0kwHBDBZ4="; - postOverlayPlugin = '' - cp "${src}/external_plugin_deps.bzl" "$out/plugins/external_plugin_deps.bzl" - ''; -} diff --git a/services/gerrit/default.nix b/services/gerrit/default.nix index 065534e..8e1ae5e 100644 --- a/services/gerrit/default.nix +++ b/services/gerrit/default.nix @@ -6,6 +6,8 @@ let inherit (lib) mkEnableOption mkIf mkOption types; cfgGerrit = config.services.gerrit; cfg = config.bagel.services.gerrit; + + jdk = pkgs.openjdk21_headless; in { options.bagel.services.gerrit = { @@ -28,7 +30,7 @@ in config = mkIf cfg.enable { networking.firewall.allowedTCPPorts = [ 29418 ]; - environment.systemPackages = [ pkgs.openjdk17_headless ]; + environment.systemPackages = [ jdk ]; fileSystems."/var/lib/gerrit" = mkIf (cfg.data != "/var/lib/gerrit") { device = cfg.data; @@ -64,12 +66,7 @@ in jvmHeapLimit = "32g"; - # In some NixOS channel bump, the default version of OpenJDK has - # changed to one that is incompatible with our current version of - # Gerrit. - # - # TODO(tazjin): Update Gerrit and remove this when possible. - jvmPackage = pkgs.openjdk17_headless; + jvmPackage = jdk; settings = { # Performance settings