services/gerrit: migrate to Gerrit from the-distro/nix-gerrit flake
This commit is contained in:
parent
48579e8818
commit
8a9ff8c40d
21
flake.lock
21
flake.lock
|
@ -229,6 +229,26 @@
|
||||||
"url": "https://git@git.lix.systems/lix-project/lix"
|
"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": {
|
"nix2container": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
|
@ -317,6 +337,7 @@
|
||||||
"hydra",
|
"hydra",
|
||||||
"nix"
|
"nix"
|
||||||
],
|
],
|
||||||
|
"nix-gerrit": "nix-gerrit",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"terranix": "terranix"
|
"terranix": "terranix"
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
hydra.url = "git+https://git.lix.systems/lix-project/hydra.git";
|
hydra.url = "git+https://git.lix.systems/lix-project/hydra.git";
|
||||||
hydra.inputs.nixpkgs.follows = "nixpkgs";
|
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";
|
lix.follows = "hydra/nix";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,6 +28,7 @@
|
||||||
overlays = [
|
overlays = [
|
||||||
inputs.hydra.overlays.default
|
inputs.hydra.overlays.default
|
||||||
inputs.lix.overlays.default
|
inputs.lix.overlays.default
|
||||||
|
inputs.nix-gerrit.overlays.default
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
lib = pkgs.lib;
|
lib = pkgs.lib;
|
||||||
|
@ -69,6 +73,7 @@
|
||||||
overlays = [
|
overlays = [
|
||||||
inputs.hydra.overlays.default
|
inputs.hydra.overlays.default
|
||||||
inputs.lix.overlays.default
|
inputs.lix.overlays.default
|
||||||
|
inputs.nix-gerrit.overlays.default
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
meta.specialArgs.inputs = inputs;
|
meta.specialArgs.inputs = inputs;
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
[
|
[]
|
||||||
(import ./gerrit.nix)
|
|
||||||
]
|
|
||||||
|
|
|
@ -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 { };
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
{ makeSetupHook }:
|
|
||||||
|
|
||||||
makeSetupHook {
|
|
||||||
name = "rules_java_bazel_hook";
|
|
||||||
substitutions = {
|
|
||||||
local_java = ./local_java;
|
|
||||||
};
|
|
||||||
} ./setup-hook.sh
|
|
|
@ -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")
|
|
|
@ -1 +0,0 @@
|
||||||
workspace(name = "local_java")
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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",
|
|
||||||
)
|
|
|
@ -1 +0,0 @@
|
||||||
workspace(name = "nodejs")
|
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
exec "__NODEJS__/bin/node" "$@"
|
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
exec "__NODEJS__/bin/npm" "$@"
|
|
|
@ -1 +0,0 @@
|
||||||
workspace(name = "yarn")
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
exec "__YARN__/bin/yarn" "$@"
|
|
|
@ -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"
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
From 216843cff4a8e41ad9887118751a412c1a22ce72 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Luke Granger-Brown <git@lukegb.com>
|
|
||||||
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<string, string>([
|
|
||||||
['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
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
From 63f1ff6ea749ae2af29a53463bca81bc3f4bf25b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Luke Granger-Brown <git@lukegb.com>
|
|
||||||
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<string, string>([
|
|
||||||
['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
|
|
||||||
|
|
|
@ -1,214 +0,0 @@
|
||||||
From ca2df6d7f53441d443d42908e30bf60fbfc15392 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Luke Granger-Brown <git@lukegb.com>
|
|
||||||
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<String, String[]> urlParameterMap,
|
|
||||||
Function<String, SanitizedContent> urlInScriptTagOrdainer,
|
|
||||||
- String requestedURL)
|
|
||||||
+ String requestedURL,
|
|
||||||
+ TitleComputer titleComputer)
|
|
||||||
throws URISyntaxException, RestApiException {
|
|
||||||
ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
|
|
||||||
data.putAll(
|
|
||||||
staticTemplateData(
|
|
||||||
canonicalURL, cdnPath, faviconPath, urlParameterMap, urlInScriptTagOrdainer))
|
|
||||||
- .putAll(dynamicTemplateData(gerritApi, requestedURL, canonicalURL));
|
|
||||||
+ .putAll(dynamicTemplateData(gerritApi, requestedURL, canonicalURL, titleComputer));
|
|
||||||
Set<String> 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<String, Object> dynamicTemplateData(
|
|
||||||
- GerritApi gerritApi, String requestedURL, String canonicalURL)
|
|
||||||
+ GerritApi gerritApi, String requestedURL, String canonicalURL, TitleComputer titleComputer)
|
|
||||||
throws RestApiException, URISyntaxException {
|
|
||||||
ImmutableMap.Builder<String, Object> data = ImmutableMap.builder();
|
|
||||||
Map<String, SanitizedContent> initialData = new HashMap<>();
|
|
||||||
@@ -141,6 +143,10 @@ public class IndexHtmlUtil {
|
|
||||||
}
|
|
||||||
|
|
||||||
data.put("gerritInitialData", initialData);
|
|
||||||
+
|
|
||||||
+ Optional<String> 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<String, SanitizedContent> 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<ChangesCollection> changes) {
|
|
||||||
+ this.changes = changes;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public Optional<String> 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<Change.Id> changeId = tryExtractChange(url.getPath());
|
|
||||||
+ if (changeId.isPresent()) {
|
|
||||||
+ return titleFromChangeId(changeId.get());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return Optional.empty();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private static final Pattern extractChangeIdRegex = Pattern.compile("^/(?:c/.*/\\+/)?(?<changeId>[0-9]+)(?:/[0-9]+)?(?:/.*)?$");
|
|
||||||
+ private final Provider<ChangesCollection> changes;
|
|
||||||
+
|
|
||||||
+ private Optional<Change.Id> tryExtractChange(String path) {
|
|
||||||
+ Matcher m = extractChangeIdRegex.matcher(path);
|
|
||||||
+ if (!m.matches()) {
|
|
||||||
+ return Optional.empty();
|
|
||||||
+ }
|
|
||||||
+ return Change.Id.tryParse(m.group("changeId"));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private Optional<String> 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: ?}
|
|
||||||
<!DOCTYPE html>{\n}
|
|
||||||
<html lang="en">{\n}
|
|
||||||
<meta charset="utf-8">{\n}
|
|
||||||
- <meta name="description" content="Gerrit Code Review">{\n}
|
|
||||||
+ {if $title}<title>{$title} · Gerrit Code Review</title>{\n}{/if}
|
|
||||||
+ <meta name="description" content="{if $title}{$title} · {/if}Gerrit Code Review">{\n}
|
|
||||||
<meta name="referrer" content="never">{\n}
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">{\n}
|
|
||||||
|
|
||||||
--
|
|
||||||
2.45.1
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
def web_test_repositories():
|
|
||||||
pass
|
|
||||||
|
|
||||||
def browser_repositories(*args, **kwargs):
|
|
||||||
pass
|
|
|
@ -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}
|
|
||||||
'';
|
|
||||||
}))
|
|
|
@ -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
|
|
||||||
];
|
|
||||||
}
|
|
|
@ -1,472 +0,0 @@
|
||||||
commit 29ace6c38ac513f7ec56ca425230d5712c081043
|
|
||||||
Author: Luke Granger-Brown <git@lukegb.com>
|
|
||||||
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> 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<String> messageBuilder = ImmutableList.builder();
|
|
||||||
AtomicBoolean ownedByAllUsers = new AtomicBoolean(false);
|
|
||||||
@@ -405,9 +429,53 @@ public class CodeOwnerResolver {
|
|
||||||
ImmutableMultimap<CodeOwnerReference, CodeOwnerAnnotation> annotations) {
|
|
||||||
requireNonNull(codeOwnerReferences, "codeOwnerReferences");
|
|
||||||
|
|
||||||
+ ImmutableSet<String> 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<String, CodeOwner> 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<CodeOwner, String> usersToGroups =
|
|
||||||
+ resolvedGroups.inverse();
|
|
||||||
+
|
|
||||||
ImmutableSet<String> 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<String, CodeOwner> 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<Pair<String, CodeOwner>> resolvedGroupsCodeOwnersStream =
|
|
||||||
+ resolvedGroups.entries().stream().map(e -> Pair.of(e.getKey(), e.getValue()));
|
|
||||||
+ Streams.concat(Streams.concat(newlyResolvedCodeOwnersStream, cachedCodeOwnersStream), resolvedGroupsCodeOwnersStream)
|
|
||||||
.forEach(
|
|
||||||
p -> {
|
|
||||||
ImmutableSet.Builder<CodeOwnerAnnotation> 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<String, Collection<ExternalId>> lookupExternalIds(
|
|
||||||
ImmutableList.Builder<String> messages, ImmutableSet<String> emails) {
|
|
||||||
+ String[] actualEmails = emails.stream()
|
|
||||||
+ .filter(email -> email.contains("@"))
|
|
||||||
+ .toArray(String[]::new);
|
|
||||||
+ ImmutableSet<String> usernames = emails.stream()
|
|
||||||
+ .filter(email -> !email.contains("@"))
|
|
||||||
+ .collect(ImmutableSet.toImmutableSet());
|
|
||||||
try {
|
|
||||||
- ImmutableMap<String, Collection<ExternalId>> extIdsByEmail =
|
|
||||||
- externalIdCache.byEmails(emails.toArray(new String[0])).asMap();
|
|
||||||
+ ImmutableMap<String, Collection<ExternalId>> extIds =
|
|
||||||
+ new ImmutableMap.Builder<String, Collection<ExternalId>>()
|
|
||||||
+ .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> 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<CodeOwner> 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<CodeOwner> result =
|
|
||||||
@@ -127,6 +142,18 @@ public class CodeOwnerResolverTest extends AbstractCodeOwnersTest {
|
|
||||||
CodeOwnerResolver.ALL_USERS_WILDCARD));
|
|
||||||
}
|
|
||||||
|
|
||||||
+ @Test
|
|
||||||
+ public void cannotResolveCodeOwnerReferenceForGroup() throws Exception {
|
|
||||||
+ OptionalResultWithMessages<CodeOwner> 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(
|
|
|
@ -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"
|
|
||||||
'';
|
|
||||||
}
|
|
|
@ -6,6 +6,8 @@ let
|
||||||
inherit (lib) mkEnableOption mkIf mkOption types;
|
inherit (lib) mkEnableOption mkIf mkOption types;
|
||||||
cfgGerrit = config.services.gerrit;
|
cfgGerrit = config.services.gerrit;
|
||||||
cfg = config.bagel.services.gerrit;
|
cfg = config.bagel.services.gerrit;
|
||||||
|
|
||||||
|
jdk = pkgs.openjdk21_headless;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.bagel.services.gerrit = {
|
options.bagel.services.gerrit = {
|
||||||
|
@ -28,7 +30,7 @@ in
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
networking.firewall.allowedTCPPorts = [ 29418 ];
|
networking.firewall.allowedTCPPorts = [ 29418 ];
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.openjdk17_headless ];
|
environment.systemPackages = [ jdk ];
|
||||||
|
|
||||||
fileSystems."/var/lib/gerrit" = mkIf (cfg.data != "/var/lib/gerrit") {
|
fileSystems."/var/lib/gerrit" = mkIf (cfg.data != "/var/lib/gerrit") {
|
||||||
device = cfg.data;
|
device = cfg.data;
|
||||||
|
@ -64,12 +66,7 @@ in
|
||||||
|
|
||||||
jvmHeapLimit = "32g";
|
jvmHeapLimit = "32g";
|
||||||
|
|
||||||
# In some NixOS channel bump, the default version of OpenJDK has
|
jvmPackage = jdk;
|
||||||
# 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;
|
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
# Performance settings
|
# Performance settings
|
||||||
|
|
Loading…
Reference in a new issue