aboutsummaryrefslogtreecommitdiff
path: root/modules/services/gitolite
diff options
context:
space:
mode:
authorsefidel <contact@sefidel.net>2023-03-29 20:54:19 +0900
committersefidel <contact@sefidel.net>2023-04-03 18:32:29 +0900
commitce06f43476863da90dc60dcee606d2b6c5a89a8e (patch)
tree5d14946330cb09ff0ebd97bee59407fccee4d860 /modules/services/gitolite
downloadinfra-ce06f43476863da90dc60dcee606d2b6c5a89a8e.zip
project: initial commit
Diffstat (limited to 'modules/services/gitolite')
-rw-r--r--modules/services/gitolite/default.nix108
-rw-r--r--modules/services/gitolite/fix-refs9
-rw-r--r--modules/services/gitolite/rename63
3 files changed, 180 insertions, 0 deletions
diff --git a/modules/services/gitolite/default.nix b/modules/services/gitolite/default.nix
new file mode 100644
index 0000000..c2eb975
--- /dev/null
+++ b/modules/services/gitolite/default.nix
@@ -0,0 +1,108 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.modules.services.gitolite;
+in
+{
+ options.modules.services.gitolite = {
+ enable = mkEnableOption "gitolite server";
+ adminPubkey = mkOption { type = types.str; };
+ };
+ config = mkIf cfg.enable {
+ services.openssh.enable = true;
+
+ services.gitolite = {
+ enable = true;
+ user = "git";
+ group = "git";
+ adminPubkey = cfg.adminPubkey;
+ extraGitoliteRc = ''
+ $RC{UMASK} = 0027;
+ $RC{GIT_CONFIG_KEYS} = '.*';
+ $RC{ROLES}{OWNERS} = 1;
+ $RC{OWNER_ROLENAME} = 'OWNERS';
+ # For some unknown reason, $ENV{HOME} doesn't get resolved to the correct
+ # directory.
+ # $RC{LOCAL_CODE} = '$ENV{HOME}/local';
+ $RC{LOCAL_CODE} = '/var/lib/gitolite/local';
+ push(@{$RC{ENABLE}}, 'D');
+ push(@{$RC{ENABLE}}, 'symbolic-ref');
+ push(@{$RC{ENABLE}}, 'rename');
+ push(@{$RC{POST_GIT}}, 'fix-refs');
+ # push(@{$RC{ENABLE}}, 'set-default-roles');
+ # push(@{$RC{ENABLE}}, 'create');
+ # push(@{$RC{ENABLE}}, 'fork');
+
+ '';
+ };
+
+ environment.persistence."/persist".directories = [
+ "/var/lib/gitolite"
+ ];
+
+ system.activationScripts.gitolite-create-local = ''
+ mkdir -p /var/lib/gitolite/local/triggers
+ mkdir -p /var/lib/gitolite/local/commands
+ chown -R git:git /var/lib/gitolite/local
+ '';
+
+ systemd.tmpfiles.rules = [
+ # https://groups.google.com/g/gitolite/c/NwZ1-hq9-9E/m/mDbiKyAvDwAJ
+ "C /var/lib/gitolite/local/triggers/fix-refs 755 - - - ${./fix-refs}"
+ "C /var/lib/gitolite/local/commands/rename 755 - - - ${./rename}"
+ ];
+
+
+ systemd.timers."gitolite-trash-cleanup" = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnCalendar = "*-*-* 00:00:00";
+ Unit = "gitolite-trash-cleanup.service";
+ };
+ };
+
+ systemd.services."gitolite-trash-cleanup" = {
+ script = ''
+ set -euo pipefail
+ if [ ! -d "Trash" ] ; then
+ echo Trash directory is nonexistent!
+ echo No operations to perform. Exiting.
+ exit 0
+ fi
+
+ match=$(find Trash -type d -regextype posix-extended -regex ".*/[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}:[0-9]{2}:[0-9]{2}$")
+ processed_entry=0
+ removed_entry=0
+
+ for dir in $match
+ do
+ system_timestamp=$(date +%s)
+ trash_timestamp=$(basename $dir | sed -e "s/_/ /g" | date -f - +%s)
+ age=$(( $system_timestamp - $trash_timestamp ))
+ # Wipe trashes older than 2w
+ if [[ age -gt 1209600 ]] ; then
+ echo "Removing '$dir' (age $age)"
+ rm -rf $dir
+ ((removed_entry+=1))
+ fi
+ ((processed_entry+=1))
+ done
+
+ echo "Directories that needs cleanup:"
+ find Trash -type d -empty -print -delete
+ echo "Cleaned empty directories."
+
+ echo "Done! Removed $removed_entry/$processed_entry"
+ '';
+
+ path = with pkgs; [ bash util-linux coreutils ];
+
+ serviceConfig = {
+ Type = "oneshot";
+ User = "git";
+ WorkingDirectory = "/var/lib/gitolite/repositories";
+ };
+ };
+ };
+}
diff --git a/modules/services/gitolite/fix-refs b/modules/services/gitolite/fix-refs
new file mode 100644
index 0000000..8ffec9e
--- /dev/null
+++ b/modules/services/gitolite/fix-refs
@@ -0,0 +1,9 @@
+[[ $4 == W ]] || exit 0
+
+cd $GL_REPO_BASE/$2.git
+
+head=`git symbolic-ref HEAD`
+[[ -f $head ]] || {
+ set -- refs/heads/*
+ git symbolic-ref HEAD $1
+}
diff --git a/modules/services/gitolite/rename b/modules/services/gitolite/rename
new file mode 100644
index 0000000..2b00c7a
--- /dev/null
+++ b/modules/services/gitolite/rename
@@ -0,0 +1,63 @@
+
+# Usage: ssh git@host rename [-c] <repo1> <repo2>
+#
+# Renames repo1 to repo2. You must be the creator of repo1, and have
+# create ("C") permissions for repo2, which of course must not exist.
+# Alternatively you must be an account admin, that is, you must have
+# write access to the gitolite-admin repository. If you have "C"
+# permissions for repo2 then you can use the -c option to take over
+# as creator of the repository.
+
+die() { echo "$@" >&2; exit 1; }
+usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; }
+[ -z "$1" ] && usage
+[ "$1" = "-h" ] && usage
+[ -z "$GL_USER" ] && die GL_USER not set
+
+# ----------------------------------------------------------------------
+
+if [ "$1" = "-c" ]
+then shift
+ takeover=true
+else takeover=false
+fi
+
+from="$1"; shift
+to="$1"; shift
+[ -z "$to" ] && usage
+
+topath=$GL_REPO_BASE/$to.git
+
+checkto() {
+ gitolite access -q "$to" $GL_USER ^C any ||
+ die "'$to' already exists or you are not allowed to create it"
+}
+
+if gitolite access -q gitolite-admin $GL_USER
+then
+ # the user is an admin so we can avoid most permission checks
+ if $takeover
+ then checkto
+ elif [ -e $topath ]
+ then die "'$to' already exists"
+ fi
+else
+ # the user isn't an admin, so do all the checks
+ checkto
+ gitolite creator "$from" $GL_USER ||
+ die "'$from' does not exist or you are not allowed to delete it"
+fi
+
+# ----------------------------------------------------------------------
+
+mv $GL_REPO_BASE/$from.git $topath
+[ $? -ne 0 ] && exit 1
+
+$takeover && echo $GL_USER > $topath/gl-creator
+
+# Rebuild projects.list
+gitolite trigger POST_COMPILE
+
+echo "$from renamed to $to" >&2
+
+exit