1
0
Fork 0
forked from lukas/nixos-config
nixos-config/hosts/pinix/localServices/webhook.nix
pijukka 609c27ce15 calendar: move calendar-web frontend to its own Forgejo repo
Source now lives in lukas/calendar-web instead of this flake, matching
the website/dashboard pattern: pinix checks it out at
/var/www/calendar-web, nginx serves the dist/ output directly, and a
new gitpull-calendar-web webhook hook does `git pull && npm ci && npm
run build` (esbuild) on push. Frontend/style-only changes no longer
need a nixos-rebuild.

- webhook.nix: new hook + build script
- packages.nix: add nodejs (npm needed for the build script)
- forgejo.nix: enable ENABLE_PUSH_CREATE_USER, needed to create the
  new repo by pushing to it rather than via the web UI
- web.nix: nginx root points at /var/www/calendar-web/dist
- README.md: document the new deploy path

Still needs a Forgejo-side webhook added manually in the calendar-web
repo settings (no API token available to script it): target
http://127.0.0.1:9000/hooks/gitpull-calendar-web, push events on dev.
2026-07-30 09:28:41 +02:00

196 lines
7 KiB
Nix

{ config, pkgs, ... }:
{
# Webhook service configuration for Git repository updates and automation
services.webhook = {
enable = true;
user = "drone";
group = "users";
port = 9000;
ip = "0.0.0.0";
verbose = false;
openFirewall = true;
hooks = {
# Documentation and content hooks
nog25-book = {
command-working-directory = "/var/www/data/nog25-book";
execute-command = "/etc/scripts/nog25-book.sh";
};
desk-update = {
command-working-directory = "/var/www/desk-0ff-space";
execute-command = "/etc/scripts/desk-update.sh";
};
# Git pull automation hooks
gitpull-website = {
command-working-directory = "/home/drone/script";
execute-command = "/home/drone/script/gitpull-website.sh";
};
gitpull-dashboard = {
command-working-directory = "/home/drone/script";
execute-command = "/home/drone/script/gitpull-dashboard.sh";
};
gitpull-calendar-web = {
command-working-directory = "/var/www/calendar-web";
execute-command = "/etc/scripts/gitpull-calendar-web.sh";
};
# Notification and update hooks with payload processing
wiki-update = {
command-working-directory = "/etc/scripts";
execute-command = "/etc/scripts/wiki-update.sh";
response-message = "accepted";
pass-environment-to-command = [
{ source = "entire-payload"; envname = "FORGEJO_PAYLOAD"; }
{ source = "header"; name = "X-Forgejo-Event"; envname = "FORGEJO_EVENT"; }
];
};
vikunja-update = {
command-working-directory = "/etc/scripts";
execute-command = "/etc/scripts/vikunja-update.sh";
pass-environment-to-command = [
{ source = "payload"; name = "data"; envname = "PAYLOAD_DATA"; }
{ source = "payload"; name = "event_name"; envname = "EVENT_NAME"; }
];
};
};
};
# Script definitions for webhook automation
environment.etc."scripts/gitpull-calendar-web.sh".source =
pkgs.writeShellScript "gitpull-calendar-web.sh" ''
#!/run/current-system/sw/bin/bash
set -eu
export PATH=/run/current-system/sw/bin:$PATH
PROJECT_DIR="/var/www/calendar-web"
git -C "$PROJECT_DIR" pull
cd "$PROJECT_DIR"
npm ci
npm run build
'';
environment.etc."scripts/desk-update.sh".source =
pkgs.writeShellScript "desk-update.sh" ''
#!/run/current-system/sw/bin/bash
export PATH=/run/current-system/sw/bin:$PATH
PROJECT_DIR="/var/www/desk-0ff-space"
/run/current-system/sw/bin/git -C "$PROJECT_DIR" pull
'';
environment.etc."scripts/nog25-book.sh".source =
pkgs.writeShellScript "nog25-book.sh" ''
#!/run/current-system/sw/bin/bash
export PATH=/run/current-system/sw/bin:$PATH
PROJECT_DIR="/var/www/data/nog25-book"
TEX_FILE="nationOfGondwana2025.tex"
# Pull latest changes from repository
/run/current-system/sw/bin/git -C "$PROJECT_DIR" pull
cd "$PROJECT_DIR"
# Build PDF from LaTeX source
/run/current-system/sw/bin/lualatex -interaction=nonstopmode "$TEX_FILE"
'';
environment.etc."scripts/wiki-update.sh".source =
pkgs.writeShellScript "wiki-update.sh" ''
#!/run/current-system/sw/bin/bash
set -eu
PAYLOAD="''${FORGEJO_PAYLOAD:-}"
EVENT="''${FORGEJO_EVENT:-}"
[ -n "$PAYLOAD" ] || exit 0
case "$EVENT" in
push)
REPO=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.repository.full_name // .repository.name // "unknown"')
AUTHOR=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.pusher.login // .sender.login // "unknown"')
REF=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.ref // ""')
BRANCH="''${REF#refs/heads/}"
COMMITS=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '(.commits // []) | length')
COMMIT=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.head_commit.message // ""' |
${pkgs.coreutils}/bin/tr '\r\n\t' ' ' | ${pkgs.coreutils}/bin/cut -c1-160)
URL=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.compare_url // .repository.html_url // ""')
MESSAGE="[push] $REPO: $AUTHOR → $BRANCH ($COMMITS commits)
$COMMIT
$URL"
;;
pull_request)
REPO=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.repository.full_name // .repository.name // "unknown"')
ACTION=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.action // "updated"')
NUMBER=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.number // .pull_request.number // "?"')
AUTHOR=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.sender.login // .pull_request.user.login // "unknown"')
TITLE=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.pull_request.title // ""' |
${pkgs.coreutils}/bin/tr '\r\n\t' ' ' | ${pkgs.coreutils}/bin/cut -c1-160)
HEAD=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.pull_request.head.ref // "?"')
BASE=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.pull_request.base.ref // "?"')
URL=$(printf '%s' "$PAYLOAD" | ${pkgs.jq}/bin/jq -r '.pull_request.html_url // ""')
MESSAGE="[PR $ACTION] $REPO #$NUMBER by $AUTHOR
$TITLE
$HEAD → $BASE
$URL"
;;
*)
exit 0
;;
esac
# Send XMPP notification
${pkgs.go-sendxmpp}/bin/go-sendxmpp \
--username "vikunja" \
--password "$(</run/agenix/go-sendxmpp)" \
--alias "forgeBot" \
--jserver "bot.${config.domain}" \
--chatroom "update@muc.${config.domain}" \
<<< "$MESSAGE"
'';
environment.etc."scripts/vikunja-update.sh".source =
pkgs.writeShellScript "vikunja-update.sh" ''
#!/run/current-system/sw/bin/bash
set -eu
# Extract Vikunja task data from webhook payload
AUTHOR=$(echo "$PAYLOAD_DATA" | ${pkgs.jq}/bin/jq -r '.doer.username // empty')
PROJECT=$(echo "$PAYLOAD_DATA" | ${pkgs.jq}/bin/jq -r '.task.project_id // empty')
TITLE=$(echo "$PAYLOAD_DATA" | ${pkgs.jq}/bin/jq -r '.task.title // empty')
COMMENT=$(echo "$PAYLOAD_DATA" | ${pkgs.jq}/bin/jq -r '.comment.comment // empty' | sed -E 's/<[^>]+>//g')
MESSAGE="Event: $EVENT_NAME
User: $AUTHOR
Project: $PROJECT
Task: $TITLE
Comment: $COMMENT"
# Send XMPP notification for Vikunja updates
${pkgs.go-sendxmpp}/bin/go-sendxmpp \
--username "vikunja" \
--password "$(</run/agenix/go-sendxmpp)" \
--alias "vikunjaBot" \
--jserver "bot.${config.domain}" \
--chatroom "vikunja@muc.${config.domain}" \
<<< "$MESSAGE"
# Second channel: same event as a direct message to agent@bot.${config.domain},
# so its 1:1 archive can be read on its own instead of parsing the MUC room.
${pkgs.go-sendxmpp}/bin/go-sendxmpp \
--username "vikunja" \
--password "$(</run/agenix/go-sendxmpp)" \
--jserver "bot.${config.domain}" \
"agent@bot.${config.domain}" \
<<< "$MESSAGE"
'';
}