feat(deploy): always deploy the newest code from origin/main
Three fixes so a plain './deploy.sh' really does ship the latest code: - Diverged branch: rebase local commits onto origin/main instead of dying on 'Fast-forward to origin/main failed'. Conflicts abort the rebase and stop the deploy rather than building a half-merged tree. - Unreachable origin: retry the fetch through the local mihomo proxy (HERMES_UI_GIT_PROXY, default http://127.0.0.1:7890). - Self-kill on restart: when the script runs inside the service's own cgroup, 'systemctl restart' SIGTERMs the script too, so the build landed but the post-restart health checks never ran. Re-execute under a transient systemd scope to escape the cgroup first.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
APP_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT_PATH="$APP_DIR/$(basename "$0")"
|
||||
cd "$APP_DIR"
|
||||
|
||||
SERVICE="${HERMES_UI_SERVICE:-hermes-ui.service}"
|
||||
@@ -33,6 +34,10 @@ BACKUP_DIR="$STATE_DIR/backups"
|
||||
LOCK_HASH_FILE="$STATE_DIR/lockfile.sha256"
|
||||
KEEP_BACKUPS=3
|
||||
|
||||
# gitea is not directly reachable from every host; when a plain fetch fails
|
||||
# the script retries through the local mihomo proxy.
|
||||
GIT_PROXY="${HERMES_UI_GIT_PROXY:-http://127.0.0.1:7890}"
|
||||
|
||||
HEALTH_URL="http://127.0.0.1:$PORT/health"
|
||||
AUTH_URL="http://127.0.0.1:$PORT/api/auth/status"
|
||||
|
||||
@@ -104,6 +109,31 @@ while [ $# -gt 0 ]; do
|
||||
shift
|
||||
done
|
||||
|
||||
# --- Escape the service cgroup --------------------------------------------
|
||||
#
|
||||
# This script restarts $SERVICE. When it is launched from inside that
|
||||
# service's cgroup — e.g. from the agent bridge that the web UI itself
|
||||
# runs — the restart SIGTERMs the whole cgroup, including this script.
|
||||
# The build succeeds, the service comes back, but the script dies before it
|
||||
# can run the post-restart health checks.
|
||||
#
|
||||
# Re-executing under a transient systemd scope moves the script into its
|
||||
# own cgroup, so the restart no longer takes it down with it. A script
|
||||
# started from a normal shell is not affected.
|
||||
|
||||
if [ "${HERMES_UI_DEPLOY_SCOPED:-0}" != "1" ] \
|
||||
&& [ -r /proc/self/cgroup ] \
|
||||
&& grep -q "$SERVICE" /proc/self/cgroup 2>/dev/null; then
|
||||
if command -v systemd-run >/dev/null 2>&1; then
|
||||
scope_unit="hermes-ui-deploy-$(date +%s)-$$"
|
||||
export HERMES_UI_DEPLOY_SCOPED=1
|
||||
echo "Running inside the $SERVICE cgroup — re-executing in scope $scope_unit"
|
||||
exec systemd-run --scope --quiet --unit="$scope_unit" "$SCRIPT_PATH" "$@"
|
||||
else
|
||||
warn "systemd-run not found — the restart may kill this script early."
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Preflight ------------------------------------------------------------
|
||||
|
||||
step "Preflight"
|
||||
@@ -137,6 +167,30 @@ if [ "$DRY_RUN" -eq 1 ]; then
|
||||
fi
|
||||
|
||||
# --- Pull -----------------------------------------------------------------
|
||||
#
|
||||
# The deploy must always end up building the newest code on origin/main.
|
||||
# Two things get in the way of that:
|
||||
#
|
||||
# * The branch diverged — the operator pushed from a dev machine while
|
||||
# this host also had local commits. A merge commit would be recorded
|
||||
# for every deploy; a rebase replays the local commits on top of
|
||||
# origin/main and keeps the history linear.
|
||||
# * origin is unreachable directly — gitea sits behind the network, so
|
||||
# the fetch has to go through the local proxy.
|
||||
#
|
||||
# If the rebase hits a conflict the script stops instead of deploying a
|
||||
# half-merged tree.
|
||||
|
||||
fetch_origin() {
|
||||
if git fetch --quiet origin main 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
if [ -n "$GIT_PROXY" ] && git -c "http.proxy=$GIT_PROXY" -c "https.proxy=$GIT_PROXY" \
|
||||
fetch --quiet origin main 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "$SKIP_PULL" -eq 1 ]; then
|
||||
step "Skipping git pull (--skip-pull)"
|
||||
@@ -149,10 +203,19 @@ else
|
||||
else
|
||||
# A failed fetch must not block a deploy: the point of the script is to
|
||||
# build and restart what is already checked out.
|
||||
if ! git fetch --quiet origin main; then
|
||||
if ! fetch_origin; then
|
||||
warn "Could not reach origin — continuing with the local checkout."
|
||||
elif git merge --ff-only --quiet origin/main; then
|
||||
ok "Updated to $(git rev-parse --short HEAD)"
|
||||
elif [ -n "$(git rev-list --count origin/main..HEAD)" ]; then
|
||||
# Diverged with local commits on top — rebase them onto origin/main.
|
||||
step "Local commits found, rebasing onto origin/main"
|
||||
if git rebase origin/main; then
|
||||
ok "Rebased onto $(git rev-parse --short origin/main), now at $(git rev-parse --short HEAD)"
|
||||
else
|
||||
git rebase --abort || true
|
||||
die "Rebase onto origin/main hit a conflict. Resolve it by hand and re-run."
|
||||
fi
|
||||
else
|
||||
die "Fast-forward to origin/main failed. Resolve the branch by hand and re-run."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user