Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions deploy/install-ilserver4.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
#
# Deploy one commit of the bot to ilserver4. Not run by hand: ilserver4-deploy
# (Isma-L154/Project_ilserver4) runs it as root, from its own export of that
# commit, whenever main changes one of its inputs in deploy/manifest.
#
# update.sh does the work, as the checkout's owner, so git and pip never leave
# root-owned files behind in it. It runs from this export rather than from the
# checkout, so a change to update.sh applies in the same deployment, and from a
# root-owned copy because the export is only readable by root.
#
set -euo pipefail

APP_DIR=/home/ashesofil/LoopifyBot
COMMIT="${DEPLOY_COMMIT:?set by ilserver4-deploy: the commit being deployed}"
APP_USER="$(stat -c '%U' "$APP_DIR")"

script="$(mktemp)"
trap 'rm -f "$script"' EXIT
install -m 0644 deploy/update.sh "$script"

runuser -u "$APP_USER" -- env APP_DIR="$APP_DIR" bash "$script" "$COMMIT"
11 changes: 11 additions & 0 deletions deploy/manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Read by ilserver4-deploy (Isma-L154/Project_ilserver4), which deploys main of
# this repository to ilserver4.
#
# kind path inputs: files, or directories ending in /
#
# auto runs when an input or the installer itself changes. ignore maps files no
# installer reads. Tests, docs and site/ are not inputs: changing them must not
# restart the bot.

auto deploy/install-ilserver4.sh cogs/ services/ utils/ main.py config.py requirements.txt deploy/install-units.sh deploy/update.sh deploy/update-ytdlp.sh
ignore deploy/manifest deploy/README.md deploy/setup.sh deploy/launch_ec2.sh
16 changes: 13 additions & 3 deletions deploy/update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@
# Update a deployed bot to the latest committed code and restart it.
#
# Usage, on the host:
# cd ~/LoopifyBot && bash deploy/update.sh
# cd ~/LoopifyBot && bash deploy/update.sh # pull main
# cd ~/LoopifyBot && bash deploy/update.sh COMMIT # fast-forward to COMMIT
#
# On ilserver4 it is not run by hand: deploy/install-ilserver4.sh feeds it to
# bash on stdin with APP_DIR set, which is why APP_DIR can come from outside.
#
set -euo pipefail

APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TARGET="${1:-}"
APP_DIR="${APP_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
VENV_DIR="$APP_DIR/.venv"
SERVICE_NAME="loopify-bot"

Expand Down Expand Up @@ -50,7 +55,12 @@ fi
previous="$(git rev-parse HEAD)"

echo "==> Fetching..."
git pull --ff-only
if [[ -n "$TARGET" ]]; then
git fetch --quiet origin main
git merge --quiet --ff-only "$TARGET"
else
git pull --ff-only
fi

if [[ "$previous" == "$(git rev-parse HEAD)" ]]; then
echo "==> Already up to date."
Expand Down
35 changes: 35 additions & 0 deletions tests/test_deploy_manifest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
deploy/manifest must cover every file under deploy/.

ilserver4-deploy refuses to deploy a commit with an unmapped file there, so a
new script that is not listed would stop every deployment of the bot rather
than be skipped. This catches it in the pull request instead.
"""

from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
DEPLOY = ROOT / "deploy"


def entries() -> list[tuple[str, str, list[str]]]:
lines = (DEPLOY / "manifest").read_text(encoding="utf-8").splitlines()
rows = [line.split("#", 1)[0].split() for line in lines]
return [(row[0], row[1], row[2:]) for row in rows if row]


def test_every_file_under_deploy_is_mapped():
mapped = [path for _, first, rest in entries() for path in [first, *rest]]
for file in DEPLOY.rglob("*"):
if not file.is_file():
continue
name = file.relative_to(ROOT).as_posix()
assert any(name == p or (p.endswith("/") and name.startswith(p)) for p in mapped), \
f"{name} is not in deploy/manifest"


def test_every_input_exists():
"""A misspelt input would never trigger a deployment."""
for _kind, installer, inputs in entries():
for path in [installer, *inputs]:
assert (ROOT / path).exists(), f"{path} in deploy/manifest does not exist"
Loading