diff --git a/deploy/systemd/windygit-backup.service b/deploy/systemd/windygit-backup.service new file mode 100644 index 0000000..ab6e155 --- /dev/null +++ b/deploy/systemd/windygit-backup.service @@ -0,0 +1,13 @@ +[Unit] +Description=Windy Git nightly backup (git bundles + windgit schema -> R2) +After=network-online.target docker.service + +[Service] +Type=oneshot +WorkingDirectory=/srv/windygit/src +# The .env holds the R2 credentials. The script refuses to run without them +# rather than reporting a backup that did not happen. +EnvironmentFile=/srv/windygit/src/.env +ExecStart=/bin/bash /srv/windygit/src/scripts/backup.sh +Nice=10 +IOSchedulingClass=idle diff --git a/deploy/systemd/windygit-backup.service.d/windy-job.conf b/deploy/systemd/windygit-backup.service.d/windy-job.conf new file mode 100644 index 0000000..61d5045 --- /dev/null +++ b/deploy/systemd/windygit-backup.service.d/windy-job.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=/usr/local/bin/windy-job windygit-backup 26h --expect "ok — [0-9]+ repos" --owner 13 -- /bin/bash /srv/windygit/src/scripts/backup.sh diff --git a/deploy/systemd/windygit-backup.timer b/deploy/systemd/windygit-backup.timer new file mode 100644 index 0000000..b2b0646 --- /dev/null +++ b/deploy/systemd/windygit-backup.timer @@ -0,0 +1,12 @@ +[Unit] +Description=Nightly Windy Git backup + +[Timer] +OnCalendar=*-*-* 04:17:00 +# Grant's workstation is not always on at 04:17. Without this a missed window +# is simply skipped and the backup silently never runs. +Persistent=true +RandomizedDelaySec=600 + +[Install] +WantedBy=timers.target diff --git a/deploy/systemd/windygit-ci-prune.service.d/windy-job.conf b/deploy/systemd/windygit-ci-prune.service.d/windy-job.conf new file mode 100644 index 0000000..2e42305 --- /dev/null +++ b/deploy/systemd/windygit-ci-prune.service.d/windy-job.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=/usr/local/bin/windy-job windygit-ci-prune 7h --expect "ci storage [0-9]+G" --owner 13 -- /srv/windygit/src/deploy/runner/prune.sh diff --git a/deploy/systemd/windygit-sync.service b/deploy/systemd/windygit-sync.service new file mode 100644 index 0000000..0bfd311 --- /dev/null +++ b/deploy/systemd/windygit-sync.service @@ -0,0 +1,12 @@ +[Unit] +Description=Sync GitHub -> Windy Git (Phase 1: GitHub is the source of truth) +After=network-online.target docker.service + +[Service] +Type=oneshot +WorkingDirectory=/srv/windygit/src +EnvironmentFile=/srv/windygit/src/.env +# GITHUB_TOKEN is set on the host only (root-only unit file / .env) — NEVER commit it. +Environment=GITHUB_OWNER=sneakyfree +ExecStart=/bin/bash /srv/windygit/src/scripts/sync_from_github.sh +Nice=10 diff --git a/deploy/systemd/windygit-sync.service.d/windy-job.conf b/deploy/systemd/windygit-sync.service.d/windy-job.conf new file mode 100644 index 0000000..3a184ff --- /dev/null +++ b/deploy/systemd/windygit-sync.service.d/windy-job.conf @@ -0,0 +1,3 @@ +[Service] +ExecStart= +ExecStart=/usr/local/bin/windy-job windygit-sync 20m --expect "all repos in step with GitHub" --owner 13 -- /bin/bash /srv/windygit/src/scripts/sync_from_github.sh diff --git a/deploy/systemd/windygit-sync.timer b/deploy/systemd/windygit-sync.timer new file mode 100644 index 0000000..62b1427 --- /dev/null +++ b/deploy/systemd/windygit-sync.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Keep Windy Git in step with GitHub every 5 minutes + +[Timer] +OnBootSec=3min +OnUnitActiveSec=5min +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/deploy/systemd/windygit-tunnel.service b/deploy/systemd/windygit-tunnel.service new file mode 100644 index 0000000..0ed73ad --- /dev/null +++ b/deploy/systemd/windygit-tunnel.service @@ -0,0 +1,16 @@ +[Unit] +Description=Windy Git - Cloudflare Tunnel (the only ingress; no inbound port is opened) +After=network-online.target +Wants=network-online.target + +[Service] +Type=notify +ExecStart=/usr/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run +Restart=always +RestartSec=5 +# G1.4 - bounded, so a misbehaving ingress can never starve Grant's workstation. +MemoryMax=512M +CPUQuota=100% + +[Install] +WantedBy=multi-user.target diff --git a/scripts/sync_from_github.sh b/scripts/sync_from_github.sh index f051a30..25b7630 100755 --- a/scripts/sync_from_github.sh +++ b/scripts/sync_from_github.sh @@ -40,6 +40,12 @@ FAILED=0 # it flips to Windy-Git-first, or the sync will fight its authors and win. REPOS="${SYNC_REPOS:-windy-calendar windy-search windy-registry Windy-Clone WindyCloud windy-cloud-sites windy-mind eternitas windy-agent windy-git windy-chat windy-mail windy-connect windy-drops windy-code-web windy-code windy-traveler windy-translate windytranslate-site windytraveler-site windy-hand windy-cloud-domains windy-cloud-vps windytalk windy-pro}" +# Repos whose TAGS must not reach Windy Git. A tag push fires `on: push: tags` +# workflows; windy-pro's build-electron is a matrix over ubuntu/macos/windows- +# latest, labels no runner here has, so every leg would queue forever (and +# queued jobs are invisible in /actions/tasks). Releases are built elsewhere. +NO_TAGS="${SYNC_NO_TAGS:-windy-pro}" + mkdir -p "$WORK" log() { printf '[sync %s] %s\n' "$(date -u +%H:%M:%SZ)" "$*"; } @@ -63,7 +69,7 @@ for r in $REPOS; do if git --git-dir="$bare" push --quiet --force \ "https://${WG_OWNER}:${GITEA_ADMIN_TOKEN}@${WG}/${WG_OWNER}/${r}.git" \ - '+refs/heads/*:refs/heads/*' '+refs/tags/*:refs/tags/*' 2>/dev/null; then + '+refs/heads/*:refs/heads/*' $([[ " $NO_TAGS " == *" $r "* ]] || echo '+refs/tags/*:refs/tags/*') 2>/dev/null; then log "$r ok (${before:0:7})" else log "FAILED push $r -> windy git"; FAILED=1