Merge pull request #82929 from zimbatm/nixos-gerrit
nixos gerrit module
This commit is contained in:
commit
d8f0c5407e
|
@ -126,6 +126,59 @@ rec {
|
||||||
# map input to ini sections
|
# map input to ini sections
|
||||||
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
|
mapAttrsToStringsSep "\n" mkSection attrsOfAttrs;
|
||||||
|
|
||||||
|
/* Generate a git-config file from an attrset.
|
||||||
|
*
|
||||||
|
* It has two major differences from the regular INI format:
|
||||||
|
*
|
||||||
|
* 1. values are indented with tabs
|
||||||
|
* 2. sections can have sub-sections
|
||||||
|
*
|
||||||
|
* generators.toGitINI {
|
||||||
|
* url."ssh://git@github.com/".insteadOf = "https://github.com";
|
||||||
|
* user.name = "edolstra";
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
*> [url "ssh://git@github.com/"]
|
||||||
|
*> insteadOf = https://github.com/
|
||||||
|
*>
|
||||||
|
*> [user]
|
||||||
|
*> name = edolstra
|
||||||
|
*/
|
||||||
|
toGitINI = attrs:
|
||||||
|
with builtins;
|
||||||
|
let
|
||||||
|
mkSectionName = name:
|
||||||
|
let
|
||||||
|
containsQuote = libStr.hasInfix ''"'' name;
|
||||||
|
sections = libStr.splitString "." name;
|
||||||
|
section = head sections;
|
||||||
|
subsections = tail sections;
|
||||||
|
subsection = concatStringsSep "." subsections;
|
||||||
|
in if containsQuote || subsections == [ ] then
|
||||||
|
name
|
||||||
|
else
|
||||||
|
''${section} "${subsection}"'';
|
||||||
|
|
||||||
|
# generation for multiple ini values
|
||||||
|
mkKeyValue = k: v:
|
||||||
|
let mkKeyValue = mkKeyValueDefault { } " = " k;
|
||||||
|
in concatStringsSep "\n" (map (kv: "\t" + mkKeyValue kv) (lib.toList v));
|
||||||
|
|
||||||
|
# converts { a.b.c = 5; } to { "a.b".c = 5; } for toINI
|
||||||
|
gitFlattenAttrs = let
|
||||||
|
recurse = path: value:
|
||||||
|
if isAttrs value then
|
||||||
|
lib.mapAttrsToList (name: value: recurse ([ name ] ++ path) value) value
|
||||||
|
else if length path > 1 then {
|
||||||
|
${concatStringsSep "." (lib.reverseList (tail path))}.${head path} = value;
|
||||||
|
} else {
|
||||||
|
${head path} = value;
|
||||||
|
};
|
||||||
|
in attrs: lib.foldl lib.recursiveUpdate { } (lib.flatten (recurse [ ] attrs));
|
||||||
|
|
||||||
|
toINI_ = toINI { inherit mkKeyValue mkSectionName; };
|
||||||
|
in
|
||||||
|
toINI_ (gitFlattenAttrs attrs);
|
||||||
|
|
||||||
/* Generates JSON from an arbitrary (non-function) value.
|
/* Generates JSON from an arbitrary (non-function) value.
|
||||||
* For more information see the documentation of the builtin.
|
* For more information see the documentation of the builtin.
|
||||||
|
|
|
@ -821,6 +821,7 @@
|
||||||
./services/web-apps/documize.nix
|
./services/web-apps/documize.nix
|
||||||
./services/web-apps/dokuwiki.nix
|
./services/web-apps/dokuwiki.nix
|
||||||
./services/web-apps/frab.nix
|
./services/web-apps/frab.nix
|
||||||
|
./services/web-apps/gerrit.nix
|
||||||
./services/web-apps/gotify-server.nix
|
./services/web-apps/gotify-server.nix
|
||||||
./services/web-apps/grocy.nix
|
./services/web-apps/grocy.nix
|
||||||
./services/web-apps/icingaweb2/icingaweb2.nix
|
./services/web-apps/icingaweb2/icingaweb2.nix
|
||||||
|
|
218
nixos/modules/services/web-apps/gerrit.nix
Normal file
218
nixos/modules/services/web-apps/gerrit.nix
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.gerrit;
|
||||||
|
|
||||||
|
# NixOS option type for git-like configs
|
||||||
|
gitIniType = with types;
|
||||||
|
let
|
||||||
|
primitiveType = either str (either bool int);
|
||||||
|
multipleType = either primitiveType (listOf primitiveType);
|
||||||
|
sectionType = lazyAttrsOf multipleType;
|
||||||
|
supersectionType = lazyAttrsOf (either multipleType sectionType);
|
||||||
|
in lazyAttrsOf supersectionType;
|
||||||
|
|
||||||
|
gerritConfig = pkgs.writeText "gerrit.conf" (
|
||||||
|
lib.generators.toGitINI cfg.settings
|
||||||
|
);
|
||||||
|
|
||||||
|
# Wrap the gerrit java with all the java options so it can be called
|
||||||
|
# like a normal CLI app
|
||||||
|
gerrit-cli = pkgs.writeShellScriptBin "gerrit" ''
|
||||||
|
set -euo pipefail
|
||||||
|
jvmOpts=(
|
||||||
|
${lib.escapeShellArgs cfg.jvmOpts}
|
||||||
|
-Xmx${cfg.jvmHeapLimit}
|
||||||
|
)
|
||||||
|
exec ${cfg.jvmPackage}/bin/java \
|
||||||
|
"''${jvmOpts[@]}" \
|
||||||
|
-jar ${cfg.package}/webapps/${cfg.package.name}.war \
|
||||||
|
"$@"
|
||||||
|
'';
|
||||||
|
|
||||||
|
gerrit-plugins = pkgs.runCommand
|
||||||
|
"gerrit-plugins"
|
||||||
|
{
|
||||||
|
buildInputs = [ gerrit-cli ];
|
||||||
|
}
|
||||||
|
''
|
||||||
|
shopt -s nullglob
|
||||||
|
mkdir $out
|
||||||
|
|
||||||
|
for name in ${toString cfg.builtinPlugins}; do
|
||||||
|
echo "Installing builtin plugin $name.jar"
|
||||||
|
gerrit cat plugins/$name.jar > $out/$name.jar
|
||||||
|
done
|
||||||
|
|
||||||
|
for file in ${toString cfg.plugins}; do
|
||||||
|
name=$(echo "$file" | cut -d - -f 2-)
|
||||||
|
echo "Installing plugin $name"
|
||||||
|
ln -sf "$file" $out/$name
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
services.gerrit = {
|
||||||
|
enable = mkEnableOption "Gerrit service";
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.gerrit;
|
||||||
|
description = "Gerrit package to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
jvmPackage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.jre_headless;
|
||||||
|
defaultText = "pkgs.jre_headless";
|
||||||
|
description = "Java Runtime Environment package to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
jvmOpts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [
|
||||||
|
"-Dflogger.backend_factory=com.google.common.flogger.backend.log4j.Log4jBackendFactory#getInstance"
|
||||||
|
"-Dflogger.logging_context=com.google.gerrit.server.logging.LoggingContext#getInstance"
|
||||||
|
];
|
||||||
|
description = "A list of JVM options to start gerrit with.";
|
||||||
|
};
|
||||||
|
|
||||||
|
jvmHeapLimit = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "1024m";
|
||||||
|
description = ''
|
||||||
|
How much memory to allocate to the JVM heap
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
listenAddress = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "[::]:8080";
|
||||||
|
description = ''
|
||||||
|
<literal>hostname:port</literal> to listen for HTTP traffic.
|
||||||
|
|
||||||
|
This is bound using the systemd socket activation.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
type = gitIniType;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Gerrit configuration. This will be generated to the
|
||||||
|
<literal>etc/gerrit.config</literal> file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
plugins = mkOption {
|
||||||
|
type = types.listOf types.package;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
List of plugins to add to Gerrit. Each derivation is a jar file
|
||||||
|
itself where the name of the derivation is the name of plugin.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
builtinPlugins = mkOption {
|
||||||
|
type = types.listOf (types.enum cfg.package.passthru.plugins);
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
List of builtins plugins to install. Those are shipped in the
|
||||||
|
<literal>gerrit.war</literal> file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
serverId = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
Set a UUID that uniquely identifies the server.
|
||||||
|
|
||||||
|
This can be generated with
|
||||||
|
<literal>nix-shell -p utillinux --run uuidgen</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
services.gerrit.settings = {
|
||||||
|
cache.directory = "/var/cache/gerrit";
|
||||||
|
container.heapLimit = cfg.jvmHeapLimit;
|
||||||
|
gerrit.basePath = lib.mkDefault "git";
|
||||||
|
gerrit.serverId = cfg.serverId;
|
||||||
|
httpd.inheritChannel = "true";
|
||||||
|
httpd.listenUrl = lib.mkDefault "http://${cfg.listenAddress}";
|
||||||
|
index.type = lib.mkDefault "lucene";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Add the gerrit CLI to the system to run `gerrit init` and friends.
|
||||||
|
environment.systemPackages = [ gerrit-cli ];
|
||||||
|
|
||||||
|
systemd.sockets.gerrit = {
|
||||||
|
unitConfig.Description = "Gerrit HTTP socket";
|
||||||
|
wantedBy = [ "sockets.target" ];
|
||||||
|
listenStreams = [ cfg.listenAddress ];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.gerrit = {
|
||||||
|
description = "Gerrit";
|
||||||
|
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
requires = [ "gerrit.socket" ];
|
||||||
|
after = [ "gerrit.socket" "network.target" ];
|
||||||
|
|
||||||
|
path = [
|
||||||
|
gerrit-cli
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.git
|
||||||
|
pkgs.openssh
|
||||||
|
];
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
GERRIT_HOME = "%S/gerrit";
|
||||||
|
GERRIT_TMP = "%T";
|
||||||
|
HOME = "%S/gerrit";
|
||||||
|
XDG_CONFIG_HOME = "%S/gerrit/.config";
|
||||||
|
};
|
||||||
|
|
||||||
|
preStart = ''
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# bootstrap if nothing exists
|
||||||
|
if [[ ! -d git ]]; then
|
||||||
|
gerrit init --batch --no-auto-start
|
||||||
|
fi
|
||||||
|
|
||||||
|
# install gerrit.war for the plugin manager
|
||||||
|
rm -rf bin
|
||||||
|
mkdir bin
|
||||||
|
ln -sfv ${cfg.package}/webapps/${cfg.package.name}.war bin/gerrit.war
|
||||||
|
|
||||||
|
# copy the config, keep it mutable because Gerrit
|
||||||
|
ln -sfv ${gerritConfig} etc/gerrit.config
|
||||||
|
|
||||||
|
# install the plugins
|
||||||
|
rm -rf plugins
|
||||||
|
ln -sv ${gerrit-plugins} plugins
|
||||||
|
''
|
||||||
|
;
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
CacheDirectory = "gerrit";
|
||||||
|
DynamicUser = true;
|
||||||
|
ExecStart = "${gerrit-cli}/bin/gerrit daemon --console-log";
|
||||||
|
LimitNOFILE = 4096;
|
||||||
|
StandardInput = "socket";
|
||||||
|
StandardOutput = "journal";
|
||||||
|
StateDirectory = "gerrit";
|
||||||
|
WorkingDirectory = "%S/gerrit";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
meta.maintainers = with lib.maintainers; [ edef zimbatm ];
|
||||||
|
}
|
|
@ -97,6 +97,7 @@ in
|
||||||
fontconfig-default-fonts = handleTest ./fontconfig-default-fonts.nix {};
|
fontconfig-default-fonts = handleTest ./fontconfig-default-fonts.nix {};
|
||||||
freeswitch = handleTest ./freeswitch.nix {};
|
freeswitch = handleTest ./freeswitch.nix {};
|
||||||
fsck = handleTest ./fsck.nix {};
|
fsck = handleTest ./fsck.nix {};
|
||||||
|
gerrit = handleTest ./gerrit.nix {};
|
||||||
gotify-server = handleTest ./gotify-server.nix {};
|
gotify-server = handleTest ./gotify-server.nix {};
|
||||||
grocy = handleTest ./grocy.nix {};
|
grocy = handleTest ./grocy.nix {};
|
||||||
gitdaemon = handleTest ./gitdaemon.nix {};
|
gitdaemon = handleTest ./gitdaemon.nix {};
|
||||||
|
|
56
nixos/tests/gerrit.nix
Normal file
56
nixos/tests/gerrit.nix
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import ./make-test-python.nix ({ pkgs, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
lfs = pkgs.fetchurl {
|
||||||
|
url = "https://gerrit-ci.gerritforge.com/job/plugin-lfs-bazel-master/90/artifact/bazel-bin/plugins/lfs/lfs.jar";
|
||||||
|
sha256 = "023b0kd8djm3cn1lf1xl67yv3j12yl8bxccn42lkfmwxjwjfqw6h";
|
||||||
|
};
|
||||||
|
|
||||||
|
in {
|
||||||
|
name = "gerrit";
|
||||||
|
|
||||||
|
meta = with pkgs.stdenv.lib.maintainers; {
|
||||||
|
maintainers = [ flokli zimbatm ];
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes = {
|
||||||
|
server =
|
||||||
|
{ config, pkgs, ... }: {
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 2222 ];
|
||||||
|
|
||||||
|
virtualisation.memorySize = 1024;
|
||||||
|
|
||||||
|
services.gerrit = {
|
||||||
|
enable = true;
|
||||||
|
serverId = "aa76c84b-50b0-4711-a0a0-1ee30e45bbd0";
|
||||||
|
listenAddress = "[::]:80";
|
||||||
|
jvmPackage = pkgs.jdk12_headless;
|
||||||
|
jvmHeapLimit = "1g";
|
||||||
|
|
||||||
|
plugins = [ lfs ];
|
||||||
|
builtinPlugins = [ "hooks" "webhooks" ];
|
||||||
|
settings = {
|
||||||
|
gerrit.canonicalWebUrl = "http://server";
|
||||||
|
lfs.plugin = "lfs";
|
||||||
|
plugins.allowRemoteAdmin = true;
|
||||||
|
sshd.listenAddress = "[::]:2222";
|
||||||
|
sshd.advertisedAddress = "[::]:2222";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
client =
|
||||||
|
{ ... }: {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
server.wait_for_unit("gerrit.service")
|
||||||
|
server.wait_for_open_port(80)
|
||||||
|
client.succeed("curl http://server")
|
||||||
|
|
||||||
|
server.wait_for_open_port(2222)
|
||||||
|
client.succeed("nc -z server 2222")
|
||||||
|
'';
|
||||||
|
})
|
|
@ -14,6 +14,24 @@ stdenv.mkDerivation rec {
|
||||||
ln -s ${src} "$out"/webapps/gerrit-${version}.war
|
ln -s ${src} "$out"/webapps/gerrit-${version}.war
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
# A list of plugins that are part of the gerrit.war file.
|
||||||
|
# Use `java -jar gerrit.war ls | grep plugins/` to generate that list.
|
||||||
|
plugins = [
|
||||||
|
"codemirror-editor"
|
||||||
|
"commit-message-length-validator"
|
||||||
|
"delete-project"
|
||||||
|
"download-commands"
|
||||||
|
"gitiles"
|
||||||
|
"hooks"
|
||||||
|
"plugin-manager"
|
||||||
|
"replication"
|
||||||
|
"reviewnotes"
|
||||||
|
"singleusergroup"
|
||||||
|
"webhooks"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
meta = with stdenv.lib; {
|
meta = with stdenv.lib; {
|
||||||
homepage = "https://www.gerritcodereview.com/index.md";
|
homepage = "https://www.gerritcodereview.com/index.md";
|
||||||
license = licenses.asl20;
|
license = licenses.asl20;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user