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
|
set -euo pipefail
|
||||||
|
|
||||||
APP_DIR="$(cd "$(dirname "$0")" && pwd)"
|
APP_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
SCRIPT_PATH="$APP_DIR/$(basename "$0")"
|
||||||
cd "$APP_DIR"
|
cd "$APP_DIR"
|
||||||
|
|
||||||
SERVICE="${HERMES_UI_SERVICE:-hermes-ui.service}"
|
SERVICE="${HERMES_UI_SERVICE:-hermes-ui.service}"
|
||||||
@@ -33,6 +34,10 @@ BACKUP_DIR="$STATE_DIR/backups"
|
|||||||
LOCK_HASH_FILE="$STATE_DIR/lockfile.sha256"
|
LOCK_HASH_FILE="$STATE_DIR/lockfile.sha256"
|
||||||
KEEP_BACKUPS=3
|
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"
|
HEALTH_URL="http://127.0.0.1:$PORT/health"
|
||||||
AUTH_URL="http://127.0.0.1:$PORT/api/auth/status"
|
AUTH_URL="http://127.0.0.1:$PORT/api/auth/status"
|
||||||
|
|
||||||
@@ -104,6 +109,31 @@ while [ $# -gt 0 ]; do
|
|||||||
shift
|
shift
|
||||||
done
|
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 ------------------------------------------------------------
|
# --- Preflight ------------------------------------------------------------
|
||||||
|
|
||||||
step "Preflight"
|
step "Preflight"
|
||||||
@@ -137,6 +167,30 @@ if [ "$DRY_RUN" -eq 1 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# --- Pull -----------------------------------------------------------------
|
# --- 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
|
if [ "$SKIP_PULL" -eq 1 ]; then
|
||||||
step "Skipping git pull (--skip-pull)"
|
step "Skipping git pull (--skip-pull)"
|
||||||
@@ -149,10 +203,19 @@ else
|
|||||||
else
|
else
|
||||||
# A failed fetch must not block a deploy: the point of the script is to
|
# A failed fetch must not block a deploy: the point of the script is to
|
||||||
# build and restart what is already checked out.
|
# 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."
|
warn "Could not reach origin — continuing with the local checkout."
|
||||||
elif git merge --ff-only --quiet origin/main; then
|
elif git merge --ff-only --quiet origin/main; then
|
||||||
ok "Updated to $(git rev-parse --short HEAD)"
|
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
|
else
|
||||||
die "Fast-forward to origin/main failed. Resolve the branch by hand and re-run."
|
die "Fast-forward to origin/main failed. Resolve the branch by hand and re-run."
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user