Add a script to put the ingest Mac on the repo

The nightly Drive backup runs on the ingest Mac (the one whose account is
"Studio"), from a copy of this project made before the repo existed. Fixes made
anywhere else therefore never reach the machine that actually runs the backup at
04:15 — which is how the fix for a silent backup failure could itself sit unused.

adopt-repo.sh converts that folder into a clone without losing the things git
deliberately does not carry: server/.env, the Play upload keystore and its
properties, ios-signing.config and local.properties. It renames the old folder
rather than deleting it, restores those files into the clone, re-points the
LaunchAgent, and puts the old folder back if the clone fails. --dry-run prints
the plan and changes nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-09-24 14:30:32 -04:00
co-authored by Claude Opus 5
parent ff6785b800
commit 4429ae70b7
+136
View File
@@ -0,0 +1,136 @@
#!/bin/bash
# adopt-repo.sh — turn an existing, unversioned checklist folder into a clone of the repo,
# keeping every secret and every local setting that git deliberately does not carry.
#
# Written for the ingest Mac (the one whose user account is "Studio"), which still runs the
# nightly Drive backup from a copy of this project that predates the repo. Until it has this,
# fixes made anywhere else never reach the machine that actually runs the backup at 04:15.
#
# Safe to re-run. It never deletes the old folder — it renames it and leaves it in place.
#
# bash adopt-repo.sh # do it
# bash adopt-repo.sh --dry-run # print the plan and change nothing
set -uo pipefail
REPO="http://chronicles-ab.waterschurch.org:3000/christian/recurring-checklist.git"
DEST="$HOME/Documents/recurring-checklist-app"
STAMP="$(date +%Y%m%d-%H%M%S)"
KEEP="$DEST.before-git-$STAMP"
DRY=0
[ "${1:-}" = "--dry-run" ] && DRY=1
say() { printf '%s\n' "$*"; }
step() { printf '\n== %s\n' "$*"; }
run() { if [ $DRY -eq 1 ]; then printf ' would: %s\n' "$*"; else eval "$@"; fi; }
die() { printf '\n✗ %s\n' "$*" >&2; exit 1; }
# The gitignored files. These are the whole reason this is a careful script and not a
# `rm -rf` followed by a clone: none of them are in the repo and some cannot be reissued.
SECRETS=(
"server/.env"
"mobile/keystore.properties"
"mobile/keystore/upload-keystore.jks"
"mobile/ios-signing.config"
"mobile/android/local.properties"
)
step "Checking what is here"
[ -d "$DEST" ] || die "No folder at $DEST — nothing to adopt. Just clone the repo instead."
if [ -d "$DEST/.git" ]; then
say " $DEST is already a git checkout — pulling instead of re-cloning."
run "cd '$DEST' && git pull --ff-only"
say " Done. Skipping the rest; secrets were never touched."
exit 0
fi
[ -f "$DEST/backup-to-drive.sh" ] || die "$DEST does not look like the checklist project."
say " Found an unversioned project at $DEST"
step "Checking the secrets that must survive"
MISSING=0
for f in "${SECRETS[@]}"; do
if [ -e "$DEST/$f" ]; then say " ✓ $f"; else say " · $f (absent — will skip)"; MISSING=$((MISSING+1)); fi
done
[ -f "$DEST/server/.env" ] || die "server/.env is missing. It is not in the repo and not in the signing DMG. Stopping rather than producing a half-working machine."
step "Checking the forge is reachable"
curl -fsS -o /dev/null --max-time 15 "http://chronicles-ab.waterschurch.org:3000/api/v1/version" \
|| die "Cannot reach the Gitea. This machine must be on the church network."
say " ✓ reachable"
step "Renaming the old folder out of the way (kept, not deleted)"
run "mv '$DEST' '$KEEP'"
say " old folder -> $KEEP"
step "Cloning"
if [ $DRY -eq 0 ]; then
if ! git clone "$REPO" "$DEST"; then
say " clone failed — putting the old folder back"
rm -rf "$DEST"; mv "$KEEP" "$DEST"
die "Clone failed and nothing was changed. If it asked for credentials, run:
git config --global credential.helper osxkeychain
then retry; git will ask once for username 'christian' and a Gitea token
(Settings > Applications in the web UI) and remember it."
fi
else
say " would: git clone $REPO $DEST"
fi
step "Restoring the secrets and local settings"
for f in "${SECRETS[@]}"; do
if [ -e "$KEEP/$f" ]; then
run "mkdir -p '$(dirname "$DEST/$f")'"
run "cp -p '$KEEP/$f' '$DEST/$f'"
say " ✓ $f"
fi
done
step "Fixing the paths a move always breaks"
run "sed -i '' 's|^storeFile=.*|storeFile=$DEST/mobile/keystore/upload-keystore.jks|' '$DEST/mobile/keystore.properties' 2>/dev/null || true"
say " keystore.properties storeFile -> $DEST/..."
step "Making sure failures can reach a person"
if [ $DRY -eq 0 ] && ! grep -q '^ALERT_EMAIL=' "$DEST/server/.env" 2>/dev/null; then
printf '\n# Where breakage is reported (comma separated). Falls back to REPORT_EMAIL.\nALERT_EMAIL=christian@waterschurch.org,media@waterschurch.org\n' >> "$DEST/server/.env"
say " added ALERT_EMAIL to server/.env"
else
say " ALERT_EMAIL already set (or dry run)"
fi
step "Installing server dependencies (alert.js needs nodemailer)"
if [ $DRY -eq 0 ]; then
( cd "$DEST/server" && npm install --no-audit --no-fund >/dev/null 2>&1 ) \
&& say " ✓ installed" || say " ! npm install failed — alerts will not send until this works"
else
say " would: npm install in server/"
fi
step "Pointing the nightly backup at the new folder"
PLIST="$HOME/Library/LaunchAgents/org.waterschurch.checklist-drive-backup.plist"
if [ -f "$PLIST" ]; then
run "launchctl unload '$PLIST' 2>/dev/null || true"
run "sed -i '' 's|$KEEP|$DEST|g' '$PLIST'"
run "launchctl load '$PLIST'"
say " LaunchAgent reloaded against $DEST"
say " (check it still points at the right script:)"
[ $DRY -eq 0 ] && grep -o '/Users/[^<]*backup-to-drive.sh' "$PLIST" | sed 's/^/ /'
else
say " ! No LaunchAgent at $PLIST — the nightly backup is not scheduled on this Mac."
fi
step "Storing the NAS password in this Mac's keychain"
if security find-generic-password -s checklist-nas -a Christian >/dev/null 2>&1; then
say " ✓ already stored"
else
say " Not stored yet. Run this and paste the NAS password when prompted:"
say " security add-generic-password -U -s checklist-nas -a Christian -w"
say " (it is in the checklist-signing DMG, server/nas-ssh-password.txt)"
fi
step "Proving it works"
say " Run the backup by hand once and watch it:"
say " cd $DEST && ./backup-to-drive.sh"
say ""
say "Done. The old folder is still at:"
say " $KEEP"
say "Delete it once a backup run and a build have both worked."