|
|
@@ -1,16 +1,43 @@
|
|
|
-{
|
|
|
- config,
|
|
|
- lib,
|
|
|
- pkgs,
|
|
|
- ...
|
|
|
-}:
|
|
|
+{ config
|
|
|
+, lib
|
|
|
+, pkgs
|
|
|
+, ... }:
|
|
|
+
|
|
|
+with lib;
|
|
|
|
|
|
let
|
|
|
cfg = config.services.gogs;
|
|
|
- iniFormat = pkgs.formats.ini { };
|
|
|
- configFile = iniFormat.generate "gogs.ini" cfg.settings;
|
|
|
-in
|
|
|
-{
|
|
|
+
|
|
|
+ iniFormat = pkgs.formats.ini {};
|
|
|
+ defaultConfig = lib.recursiveUpdate {
|
|
|
+ server.RUN_USER = cfg.user;
|
|
|
+ security.INSTALL_LOCK = true;
|
|
|
+ database.TYPE = "sqlite3";
|
|
|
+ database.PATH = "${cfg.stateDir}/data/gogs.db";
|
|
|
+ } cfg.settings;
|
|
|
+ configFile = iniFormat.generate "gogs.ini" defaultConfig;
|
|
|
+
|
|
|
+ themeVariants = {
|
|
|
+ dark = "kristuff.gogs.dark.min.css";
|
|
|
+ dark-blue = "kristuff.gogs.dark-accent-blue.min.css";
|
|
|
+ dark-green = "kristuff.gogs.dark-accent-green.min.css";
|
|
|
+ dark-magenta = "kristuff.gogs.dark-accent-magenta.min.css";
|
|
|
+ dark-orange = "kristuff.gogs.dark-accent-orange.min.css";
|
|
|
+ dark-red = "kristuff.gogs.dark-accent-red.min.css";
|
|
|
+ dark-yellow = "kristuff.gogs.dark-accent-yellow.min.css";
|
|
|
+ };
|
|
|
+ themeFile = if cfg.theme == null then null
|
|
|
+ else if builtins.hasAttr cfg.theme themeVariants
|
|
|
+ then "${pkgs.gogs-themes}/dist/${themeVariants.${cfg.theme}}"
|
|
|
+ else cfg.theme;
|
|
|
+ themeSetupScript = pkgs.writeShellScript "gogs-theme-setup" ''
|
|
|
+ mkdir -p ${cfg.stateDir}/custom/public/css ${cfg.stateDir}/custom/templates/inject
|
|
|
+ cp -f ${themeFile} ${cfg.stateDir}/custom/public/css/theme.css
|
|
|
+ cat > ${cfg.stateDir}/custom/templates/inject/head.tmpl << 'EOF'
|
|
|
+ <link rel="stylesheet" href="{{AppSubURL}}/css/theme.css">
|
|
|
+ EOF
|
|
|
+ '';
|
|
|
+in {
|
|
|
options.services.gogs = {
|
|
|
enable = lib.mkEnableOption "Gogs Git service";
|
|
|
|
|
|
@@ -18,13 +45,13 @@ in
|
|
|
|
|
|
user = lib.mkOption {
|
|
|
type = lib.types.str;
|
|
|
- default = "gogs";
|
|
|
+ default = "git";
|
|
|
description = "User account under which Gogs runs.";
|
|
|
};
|
|
|
|
|
|
group = lib.mkOption {
|
|
|
type = lib.types.str;
|
|
|
- default = "gogs";
|
|
|
+ default = "git";
|
|
|
description = "Group under which Gogs runs.";
|
|
|
};
|
|
|
|
|
|
@@ -45,6 +72,61 @@ in
|
|
|
'';
|
|
|
};
|
|
|
|
|
|
+ theme = lib.mkOption {
|
|
|
+ type = lib.types.nullOr (
|
|
|
+ lib.types.either (lib.types.enum [
|
|
|
+ "dark"
|
|
|
+ "dark-blue"
|
|
|
+ "dark-green"
|
|
|
+ "dark-magenta"
|
|
|
+ "dark-orange"
|
|
|
+ "dark-red"
|
|
|
+ "dark-yellow"
|
|
|
+ ]) lib.types.path
|
|
|
+ );
|
|
|
+ default = null;
|
|
|
+ example = "dark-blue";
|
|
|
+ description = ''
|
|
|
+ Dark theme for Gogs. Can be:
|
|
|
+ - A string selecting a built-in variant from pkgs.gogs-themes:
|
|
|
+ dark, dark-blue, dark-green, dark-magenta, dark-orange, dark-red, dark-yellow.
|
|
|
+ - A path or package pointing to a custom CSS file.
|
|
|
+ Set to null to disable theming.
|
|
|
+ '';
|
|
|
+ };
|
|
|
+
|
|
|
+ adminUser = lib.mkOption {
|
|
|
+ type = lib.types.nullOr (lib.types.submodule {
|
|
|
+ options = {
|
|
|
+ name = lib.mkOption {
|
|
|
+ type = lib.types.str;
|
|
|
+ description = "Admin username.";
|
|
|
+ };
|
|
|
+ email = lib.mkOption {
|
|
|
+ type = lib.types.str;
|
|
|
+ description = "Admin email address.";
|
|
|
+ };
|
|
|
+ passwordFile = lib.mkOption {
|
|
|
+ type = lib.types.path;
|
|
|
+ description = ''
|
|
|
+ File containing the admin password. Must be readable by root.
|
|
|
+ Recommended to use an age secret managed by agenix.
|
|
|
+ '';
|
|
|
+ };
|
|
|
+ };
|
|
|
+ });
|
|
|
+ default = null;
|
|
|
+ example = {
|
|
|
+ email = "[email protected]";
|
|
|
+ passwordFile = "/run/secrets/gogs-admin-password";
|
|
|
+ };
|
|
|
+ description = ''
|
|
|
+ Admin user to create on first startup. Uses gogs admin create-user
|
|
|
+ via ExecStartPost. Idempotent — silently skips if the user already
|
|
|
+ exists. Set to null to skip.
|
|
|
+ '';
|
|
|
+ };
|
|
|
+
|
|
|
settings = lib.mkOption {
|
|
|
type = iniFormat.type;
|
|
|
default = { };
|
|
|
@@ -73,7 +155,7 @@ in
|
|
|
};
|
|
|
};
|
|
|
|
|
|
- config = lib.mkIf cfg.enable {
|
|
|
+ config = mkIf cfg.enable {
|
|
|
|
|
|
users.users.${cfg.user} = {
|
|
|
isSystemUser = true;
|
|
|
@@ -89,6 +171,8 @@ in
|
|
|
"d ${cfg.stateDir}/repositories 0750 ${cfg.user} ${cfg.group} -"
|
|
|
"d ${cfg.stateDir}/data 0750 ${cfg.user} ${cfg.group} -"
|
|
|
"d ${cfg.stateDir}/log 0750 ${cfg.user} ${cfg.group} -"
|
|
|
+ "d ${cfg.stateDir}/custom/public/css 0755 ${cfg.user} ${cfg.group} -"
|
|
|
+ "d ${cfg.stateDir}/custom/templates/inject 0755 ${cfg.user} ${cfg.group} -"
|
|
|
];
|
|
|
|
|
|
systemd.services.gogs = {
|
|
|
@@ -97,29 +181,45 @@ in
|
|
|
after = [ "network.target" ];
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
+ environment = {
|
|
|
+ GOGS_WORK_DIR = cfg.stateDir;
|
|
|
+ GOGS_CUSTOM = "${cfg.stateDir}/custom";
|
|
|
+ };
|
|
|
+
|
|
|
serviceConfig = {
|
|
|
Type = "simple";
|
|
|
|
|
|
User = cfg.user;
|
|
|
Group = cfg.group;
|
|
|
+ EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
|
|
|
|
|
+ StateDirectory = "gogs";
|
|
|
+ StateDirectoryMode = "0750";
|
|
|
WorkingDirectory = cfg.stateDir;
|
|
|
|
|
|
- ExecStart = "${lib.getExe cfg.package} web --config ${configFile}";
|
|
|
+ ExecStart =
|
|
|
+ "${getExe cfg.package} web --config ${configFile}";
|
|
|
+ ExecStartPre = lib.mkIf (themeFile != null) [
|
|
|
+ "+${themeSetupScript}"
|
|
|
+ ];
|
|
|
|
|
|
Restart = "on-failure";
|
|
|
|
|
|
- EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
|
|
-
|
|
|
NoNewPrivileges = true;
|
|
|
PrivateTmp = true;
|
|
|
ProtectSystem = "strict";
|
|
|
ProtectHome = true;
|
|
|
-
|
|
|
- ReadWritePaths = [
|
|
|
- cfg.stateDir
|
|
|
- ];
|
|
|
};
|
|
|
+
|
|
|
+ postStart = lib.mkIf (cfg.adminUser != null) ''
|
|
|
+ ${lib.getExe cfg.package} admin create-user \
|
|
|
+ --name ${lib.escapeShellArg cfg.adminUser.name} \
|
|
|
+ --password "$(cat ${cfg.adminUser.passwordFile})" \
|
|
|
+ --email ${lib.escapeShellArg cfg.adminUser.email} \
|
|
|
+ --admin \
|
|
|
+ --config ${configFile} \
|
|
|
+ >/dev/null 2>&1 || true
|
|
|
+ '';
|
|
|
};
|
|
|
};
|
|
|
}
|