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.
| c4e643c | 1 | #!/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 | ||
| 33 | set -Eeuo pipefail | |
| 34 | ||
| 35 | ROOT="$(cd "$(dirname "$0")/.." && pwd)" | |
| 36 | cd "$ROOT" | |
| 37 | ||
| 38 | # ── pretty printers (match scripts/install.sh style) ──────────────────────── | |
| 39 | say() { printf "\n\033[1;34m> %s\033[0m\n" "$*"; } | |
| 40 | ok() { printf " \033[32mv\033[0m %s\n" "$*"; } | |
| 41 | warn() { printf " \033[33m!\033[0m %s\n" "$*"; } | |
| 42 | fail() { printf " \033[31mx\033[0m %s\n" "$*"; exit 1; } | |
| 43 | ||
| 44 | # ── 0. Prereqs ────────────────────────────────────────────────────────────── | |
| 45 | command -v bun >/dev/null 2>&1 || fail "bun not on PATH (https://bun.sh)" | |
| 46 | ||
| 47 | DIST="$ROOT/dist" | |
| 48 | mkdir -p "$DIST" | |
| 49 | ||
| 50 | ALL_TARGETS=("linux-x64" "linux-arm64" "darwin-x64" "darwin-arm64") | |
| 51 | if [ -n "${GLUECRON_BUILD_TARGETS:-}" ]; then | |
| 52 | IFS=',' read -r -a TARGETS <<<"$GLUECRON_BUILD_TARGETS" | |
| 53 | else | |
| 54 | TARGETS=("${ALL_TARGETS[@]}") | |
| 55 | fi | |
| 56 | ||
| 57 | VERSION=$(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") | |
| 60 | say "Building Gluecron self-host binaries (v$VERSION)" | |
| 61 | ok "Targets: ${TARGETS[*]}" | |
| 62 | ok "Output: $DIST" | |
| 63 | ||
| 64 | # ── 1. Compile each target ────────────────────────────────────────────────── | |
| 65 | build_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 | ||
| 98 | FAILED=() | |
| 99 | for T in "${TARGETS[@]}"; do | |
| 100 | if ! build_one "$T"; then | |
| 101 | FAILED+=("$T") | |
| 102 | fi | |
| 103 | done | |
| 104 | ||
| 105 | # ── 2. Bundle ancillary assets ────────────────────────────────────────────── | |
| 106 | say "[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. | |
| 111 | cp -f src/hooks/post-receive.ts "$DIST/post-receive" || warn "post-receive copy failed" | |
| 112 | chmod +x "$DIST/post-receive" 2>/dev/null || true | |
| 113 | ok "post-receive hook → dist/post-receive" | |
| 114 | ||
| 115 | # Seed migrations — every SQL + migration runner needed for a fresh box. | |
| 116 | if [ -d drizzle ]; then | |
| 117 | tar -czf "$DIST/migrations.tar.gz" drizzle | |
| 118 | ok "migrations → dist/migrations.tar.gz" | |
| 119 | else | |
| 120 | warn "drizzle/ directory missing — skipped migrations bundle" | |
| 121 | fi | |
| 122 | ||
| 123 | # Default .env.example | |
| 124 | if [ -f .env.example ]; then | |
| 125 | cp -f .env.example "$DIST/env.example" | |
| 126 | ok ".env.example → dist/env.example" | |
| 127 | else | |
| 128 | warn ".env.example missing — skipped" | |
| 129 | fi | |
| 130 | ||
| 131 | # ── 3. Checksums ──────────────────────────────────────────────────────────── | |
| 132 | say "[checksums] SHA-256 for each binary" | |
| 133 | SUMFILE="$DIST/SHA256SUMS" | |
| 134 | : >"$SUMFILE" | |
| 135 | for 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 | |
| 143 | done | |
| 144 | ||
| 145 | # Include bundled ancillary assets in the combined manifest so the installer | |
| 146 | # can verify the env.example + migrations tarball too. | |
| 147 | for 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 | |
| 152 | done | |
| 153 | ok "manifest: $SUMFILE" | |
| 154 | ||
| 155 | # ── 4. VERSION + MANIFEST ─────────────────────────────────────────────────── | |
| 156 | echo "$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" | |
| 166 | ok "manifest: dist/MANIFEST.txt" | |
| 167 | ||
| 168 | if [ "${#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." | |
| 171 | fi | |
| 172 | ||
| 173 | printf "\n" | |
| 174 | printf "\033[1;32m================================================================\033[0m\n" | |
| 175 | printf "\033[1;32m GLUECRON SELF-HOST BUNDLE READY (v%s)\033[0m\n" "$VERSION" | |
| 176 | printf "\033[1;32m================================================================\033[0m\n" | |
| 177 | printf " dist: %s\n" "$DIST" | |
| 178 | printf " publish: copy dist/ to the running gluecron host so it serves\n" | |
| 179 | printf " /dist/<filename> from the binary release route.\n" | |
| 180 | printf "\n" |