-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathupdate-web.sh
More file actions
executable file
·187 lines (166 loc) · 6.24 KB
/
Copy pathupdate-web.sh
File metadata and controls
executable file
·187 lines (166 loc) · 6.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env bash
# Update, validate, build, and restart the in-repo Catalyst Code web service.
# Deploys the hub terminal workspace (primary UI at / and alias /hub).
set -Eeuo pipefail
REPO="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=scripts/cargo-local-env.sh
source "$REPO/scripts/cargo-local-env.sh"
SERVICE="${CATALYST_WEB_SERVICE:-catalyst-code-web.service}"
# Env override → PATH → common bun install location (not a machine-specific absolute).
BUN="${BUN:-$(command -v bun 2>/dev/null || true)}"
if [[ -z "$BUN" && -x "${HOME}/.bun/bin/bun" ]]; then
BUN="${HOME}/.bun/bin/bun"
fi
NODE="${NODE:-$(command -v node 2>/dev/null || true)}"
PUBLIC_ORIGIN="${CATCODE_WEB_ORIGIN:-https://cc.karutoil.site}"
LOCAL_BASE="${AUDIT_BASE:-http://127.0.0.1:49283}"
PULL=1
RUN_TESTS=1
HUB_E2E=0
CORE_PID=""
usage() {
cat <<'EOF'
Usage: ./update-web.sh [--no-pull] [--skip-tests] [--hub-e2e]
--no-pull Deploy the current checkout without fetching/pulling Git.
--skip-tests Skip type checks and web tests (build checks still run).
--hub-e2e After the service is healthy, run the authenticated /hub
browser regression (web/scripts/hub-regression.mjs) against
the deployed service. Needs AUDIT_EMAIL/AUDIT_PASSWORD in the
environment or web/.env.local, and puppeteer's browser.
Local changes are never overwritten. If tracked files have local changes, the
script skips the pull automatically and deploys the current checkout.
EOF
}
while (($#)); do
case "$1" in
--no-pull) PULL=0 ;;
--skip-tests) RUN_TESTS=0 ;;
--hub-e2e) HUB_E2E=1 ;;
-h|--help) usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
esac
shift
done
for command in git cargo curl; do
command -v "$command" >/dev/null || { echo "Missing required command: $command" >&2; exit 1; }
done
[[ -x "$BUN" ]] || { echo "Bun not found: $BUN" >&2; exit 1; }
[[ -x "$NODE" ]] || { echo "Node not found: $NODE" >&2; exit 1; }
if ((EUID == 0)); then
SYSTEMCTL=(systemctl)
else
SYSTEMCTL=(sudo systemctl)
fi
cd "$REPO"
if ((PULL)); then
if ! git diff --quiet || ! git diff --cached --quiet; then
echo "==> Tracked local changes detected; skipping pull and deploying the current checkout"
else
echo "==> Updating the checkout"
git pull --ff-only
fi
fi
stop_core_build() {
if [[ -n "${CORE_PID:-}" ]] && kill -0 "$CORE_PID" 2>/dev/null; then
kill "$CORE_PID" 2>/dev/null || true
wait "$CORE_PID" 2>/dev/null || true
fi
}
echo "==> Building the release core (all-features, ${JOBS} jobs, ${CARGO_LINKER}, overlapping web)"
(
cd "$REPO/core" && cargo build --release --locked --all-features -j"$JOBS"
) &
CORE_PID=$!
echo "==> Installing dependencies and building the SDK"
(cd sdk && "$BUN" install --frozen-lockfile && "$BUN" run build)
(cd web && "$BUN" install --frozen-lockfile)
if ((RUN_TESTS)); then
echo "==> Validating web sources"
# Drop generated App Router types from a previous deploy. After route removals
# (e.g. hub-only cleanup) stale .next/types still import deleted route modules
# and fail `tsc --noEmit` even when sources are clean. Next regenerates them
# on the build step below; the live .next tree is backed up just before that.
rm -rf web/.next/types
(cd web && "$BUN" run typecheck && "$BUN" test)
fi
# Preserve the currently served tree while Next creates a fresh .next folder.
# A failed build can therefore roll back without leaving the service broken.
BACKUP=""
SERVICE_STOPPED=0
rollback() {
local status=$?
stop_core_build
if ((status != 0)); then
echo "Update failed; restoring the previous web build" >&2
if [[ -n "$BACKUP" && -d "$BACKUP" ]]; then
rm -rf "$REPO/web/.next"
mv "$BACKUP" "$REPO/web/.next"
fi
if ((SERVICE_STOPPED)); then
"${SYSTEMCTL[@]}" restart "$SERVICE" || true
fi
fi
exit "$status"
}
trap rollback EXIT
if [[ -d web/.next ]]; then
# Keep this outside outputFileTracingRoot (the repository); otherwise Next
# may discover and attempt to trace files from the backup during its build.
BACKUP="${TMPDIR:-/tmp}/catalyst-code-web-next-backup.$$"
mv web/.next "$BACKUP"
fi
echo "==> Building the standalone web bundle with Node"
(cd web && CATCODE_WEB_ORIGIN="$PUBLIC_ORIGIN" "$NODE" node_modules/next/dist/bin/next build)
[[ -f web/.next/standalone/web/server.js || -f web/.next/standalone/server.js ]] || {
echo "Next build completed without a standalone server bundle" >&2
exit 1
}
echo "==> Waiting for the release core"
if ! wait "$CORE_PID"; then
CORE_PID=""
echo "core build failed" >&2
exit 1
fi
CORE_PID=""
echo "==> Restarting $SERVICE"
# systemd 203/EXEC if the launcher lost +x (git checkout / copy without mode bits).
if [[ -f scripts/run-web.sh ]]; then
chmod +x scripts/run-web.sh
fi
"${SYSTEMCTL[@]}" stop "$SERVICE"
SERVICE_STOPPED=1
"${SYSTEMCTL[@]}" start "$SERVICE"
health_ok() {
"${SYSTEMCTL[@]}" is-active --quiet "$SERVICE" || return 1
# Hub is auth-gated: unauthenticated it redirects (307/308) to /login.
# Either the shell (200) or the redirect proves the route built. Check both
# / (primary) and /hub (alias) so a broken root entry fails health.
local root_code hub_code
root_code="$(curl --silent --output /dev/null --write-out '%{http_code}' "$LOCAL_BASE/" || true)"
hub_code="$(curl --silent --output /dev/null --write-out '%{http_code}' "$LOCAL_BASE/hub" || true)"
[[ "$root_code" == 200 || "$root_code" == 307 || "$root_code" == 308 ]] || return 1
[[ "$hub_code" == 200 || "$hub_code" == 307 || "$hub_code" == 308 ]]
}
for attempt in {1..20}; do
if health_ok; then
SERVICE_STOPPED=0
if [[ -n "$BACKUP" && -d "$BACKUP" ]]; then
rm -rf "$BACKUP"
fi
trap - EXIT
if ((HUB_E2E)); then
echo "==> Running hub browser regression against $LOCAL_BASE"
if [[ -z "${AUDIT_EMAIL:-}" && ! -f web/.env.local ]]; then
echo "--hub-e2e: no AUDIT_EMAIL/AUDIT_PASSWORD env and no web/.env.local; skipping" >&2
else
(cd web && AUDIT_BASE="$LOCAL_BASE" "$NODE" scripts/hub-regression.mjs)
fi
fi
echo "==> Update complete: $LOCAL_BASE (hub: $LOCAL_BASE/hub)"
exit 0
fi
sleep 1
done
"${SYSTEMCTL[@]}" status "$SERVICE" --no-pager -l || true
echo "Service did not become healthy within 20 seconds" >&2
exit 1