Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

build-self-host-binary.sh

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

build-self-host-binary.shBlame180 lines · 1 contributor
c4e643cClaude1#!/usr/bin/env bash
2# =============================================================================
3# scripts/build-self-host-binary.sh
4#
5# Builds the single-binary Gluecron server distribution that ships behind
6# `curl -fsSL https://gluecron.com/install-server | bash`. Microsoft GHE is
7# a 50GB blob; this is a ~200MB binary that runs the whole platform.
8#
9# Output layout (relative to repo root, all under dist/):
10#
11# dist/
12# gluecron-server-linux-x64 (executable)
13# gluecron-server-linux-arm64 (executable)
14# gluecron-server-darwin-x64 (executable)
15# gluecron-server-darwin-arm64 (executable)
16# gluecron-server-<plat>-<arch>.sha256 (one per binary)
17# SHA256SUMS (combined manifest, served by /dist/SHA256SUMS)
18# post-receive (the bundled git hook)
19# env.example (default .env shipped with installs)
20# migrations.tar.gz (drizzle/ archive — seed schema)
21# VERSION (package.json version)
22# MANIFEST.txt (human-readable index)
23#
24# Usage:
25# scripts/build-self-host-binary.sh # builds all 4 targets
26# GLUECRON_BUILD_TARGETS="linux-x64,linux-arm64" \
27# scripts/build-self-host-binary.sh # subset (CI matrix)
28#
29# Cross-compilation uses bun's `--target` flag. Bun ≥1.1 supports
30# bun-{linux,darwin}-{x64,arm64} as compile targets.
31# =============================================================================
32
33set -Eeuo pipefail
34
35ROOT="$(cd "$(dirname "$0")/.." && pwd)"
36cd "$ROOT"
37
38# ── pretty printers (match scripts/install.sh style) ────────────────────────
39say() { printf "\n\033[1;34m> %s\033[0m\n" "$*"; }
40ok() { printf " \033[32mv\033[0m %s\n" "$*"; }
41warn() { printf " \033[33m!\033[0m %s\n" "$*"; }
42fail() { printf " \033[31mx\033[0m %s\n" "$*"; exit 1; }
43
44# ── 0. Prereqs ──────────────────────────────────────────────────────────────
45command -v bun >/dev/null 2>&1 || fail "bun not on PATH (https://bun.sh)"
46
47DIST="$ROOT/dist"
48mkdir -p "$DIST"
49
50ALL_TARGETS=("linux-x64" "linux-arm64" "darwin-x64" "darwin-arm64")
51if [ -n "${GLUECRON_BUILD_TARGETS:-}" ]; then
52 IFS=',' read -r -a TARGETS <<<"$GLUECRON_BUILD_TARGETS"
53else
54 TARGETS=("${ALL_TARGETS[@]}")
55fi
56
57VERSION=$(node -p "require('./package.json').version" 2>/dev/null \
58 || bun -e "console.log(require('./package.json').version)" 2>/dev/null \
59 || echo "0.0.0-dev")
60say "Building Gluecron self-host binaries (v$VERSION)"
61ok "Targets: ${TARGETS[*]}"
62ok "Output: $DIST"
63
64# ── 1. Compile each target ──────────────────────────────────────────────────
65build_one() {
66 local PLAT_ARCH="$1"
67 local BUN_TARGET
68 case "$PLAT_ARCH" in
69 linux-x64) BUN_TARGET="bun-linux-x64" ;;
70 linux-arm64) BUN_TARGET="bun-linux-arm64" ;;
71 darwin-x64) BUN_TARGET="bun-darwin-x64" ;;
72 darwin-arm64) BUN_TARGET="bun-darwin-arm64" ;;
73 *) fail "unknown target $PLAT_ARCH" ;;
74 esac
75
76 local OUT="$DIST/gluecron-server-$PLAT_ARCH"
77 say "[build] $PLAT_ARCH → $OUT"
78 # `--compile` produces a standalone executable bundling the bun runtime +
79 # all JS/TS source. `--minify` shaves ~15% off the binary. `--sourcemap`
80 # is intentionally omitted — we want the small ship size, and stack traces
81 # already include enough information from bun's frame info.
82 if bun build \
83 --compile \
84 --target="$BUN_TARGET" \
85 --minify \
86 --outfile "$OUT" \
87 src/index.ts; then
88 chmod +x "$OUT"
89 local SIZE
90 SIZE=$(du -h "$OUT" | awk '{print $1}')
91 ok "compiled $PLAT_ARCH ($SIZE)"
92 else
93 warn "compile failed for $PLAT_ARCH (continuing)"
94 return 1
95 fi
96}
97
98FAILED=()
99for T in "${TARGETS[@]}"; do
100 if ! build_one "$T"; then
101 FAILED+=("$T")
102 fi
103done
104
105# ── 2. Bundle ancillary assets ──────────────────────────────────────────────
106say "[bundle] hook + migrations + env.example"
107
108# post-receive hook (compiled to a single self-contained JS file the host
109# can drop into <repo>.git/hooks/). We ship the source TS too so operators
110# can audit the contents.
111cp -f src/hooks/post-receive.ts "$DIST/post-receive" || warn "post-receive copy failed"
112chmod +x "$DIST/post-receive" 2>/dev/null || true
113ok "post-receive hook → dist/post-receive"
114
115# Seed migrations — every SQL + migration runner needed for a fresh box.
116if [ -d drizzle ]; then
117 tar -czf "$DIST/migrations.tar.gz" drizzle
118 ok "migrations → dist/migrations.tar.gz"
119else
120 warn "drizzle/ directory missing — skipped migrations bundle"
121fi
122
123# Default .env.example
124if [ -f .env.example ]; then
125 cp -f .env.example "$DIST/env.example"
126 ok ".env.example → dist/env.example"
127else
128 warn ".env.example missing — skipped"
129fi
130
131# ── 3. Checksums ────────────────────────────────────────────────────────────
132say "[checksums] SHA-256 for each binary"
133SUMFILE="$DIST/SHA256SUMS"
134: >"$SUMFILE"
135for T in "${TARGETS[@]}"; do
136 BIN="$DIST/gluecron-server-$T"
137 if [ -f "$BIN" ]; then
138 HASH=$(sha256sum "$BIN" | awk '{print $1}')
139 echo "$HASH gluecron-server-$T" >>"$SUMFILE"
140 echo "$HASH" >"$BIN.sha256"
141 ok "sha256 $T ${HASH:0:12}…"
142 fi
143done
144
145# Include bundled ancillary assets in the combined manifest so the installer
146# can verify the env.example + migrations tarball too.
147for EXTRA in post-receive migrations.tar.gz env.example; do
148 if [ -f "$DIST/$EXTRA" ]; then
149 HASH=$(sha256sum "$DIST/$EXTRA" | awk '{print $1}')
150 echo "$HASH $EXTRA" >>"$SUMFILE"
151 fi
152done
153ok "manifest: $SUMFILE"
154
155# ── 4. VERSION + MANIFEST ───────────────────────────────────────────────────
156echo "$VERSION" >"$DIST/VERSION"
157
158{
159 echo "gluecron self-host bundle"
160 echo "version: $VERSION"
161 echo "built: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
162 echo
163 echo "files:"
164 (cd "$DIST" && ls -lh) | sed 's/^/ /'
165} >"$DIST/MANIFEST.txt"
166ok "manifest: dist/MANIFEST.txt"
167
168if [ "${#FAILED[@]}" -gt 0 ]; then
169 warn "Some targets failed to compile: ${FAILED[*]}"
170 warn "The bundle is incomplete but usable for the targets that succeeded."
171fi
172
173printf "\n"
174printf "\033[1;32m================================================================\033[0m\n"
175printf "\033[1;32m GLUECRON SELF-HOST BUNDLE READY (v%s)\033[0m\n" "$VERSION"
176printf "\033[1;32m================================================================\033[0m\n"
177printf " dist: %s\n" "$DIST"
178printf " publish: copy dist/ to the running gluecron host so it serves\n"
179printf " /dist/<filename> from the binary release route.\n"
180printf "\n"