From 85fecdee67057af53f79663be88b63297fa3ca44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sun, 5 Apr 2026 15:39:06 +0100 Subject: [PATCH] feat(deploy): publish-images.sh one-command ghcr upload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GHCR_TOKEN=ghp_xxx scripts/publish-images.sh 0.1.0 — logs into ghcr.io as alezmad and pushes all 3 claudemesh-* images (broker + web + migrate, multi-arch) via the existing build-multiarch.sh. Supports --dry-run that prints what would publish without logging in or pushing. When user drops their GHCR PAT, shipping the 0.1.0 image tag is one command. Also documents post-trim image sizes in DEPLOY.md Step 2 (broker 341MB, migrate 653MB, web 250MB). Co-Authored-By: Claude Opus 4.6 (1M context) --- DEPLOY.md | 20 ++++++++++++ scripts/publish-images.sh | 69 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100755 scripts/publish-images.sh diff --git a/DEPLOY.md b/DEPLOY.md index 9597313..cfaddc2 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -49,6 +49,18 @@ Three images ship: `broker`, `web`, `migrate`. Use the multi-arch build script it produces both `linux/amd64` (VPS) and `linux/arm64` (Apple Silicon devs) manifests so nobody hits QEMU emulation at runtime. +### Fast path (ghcr.io/alezmad) + +```bash +GHCR_TOKEN=ghp_xxx ./scripts/publish-images.sh 0.1.0 +./scripts/publish-images.sh 0.1.0 --dry-run # preview without pushing +``` + +One command logs in + builds + pushes all 3 images to +`ghcr.io/alezmad/claudemesh-{broker,web,migrate}` for both archs. + +### Manual path (any registry) + ```bash # Login to your registry docker login -u @@ -65,6 +77,14 @@ scripts/build-multiarch.sh ghcr.io/myorg latest # → ghcr.io/myorg/clau The script tags each image with both `` and `:latest`. Builds in ~5-8 min on Mac M-series (arm64 native is fast, amd64 via emulation is the slow leg). +Image sizes (arm64, after the `pnpm deploy` trim — amd64 is similar): + +| image | size | contains | +| ------------------- | ------- | -------------------------------------- | +| claudemesh-broker | ~341 MB | bun runtime, prod deps only | +| claudemesh-migrate | ~653 MB | bun runtime + drizzle-kit (devDep) | +| claudemesh-web | ~250 MB | node + next.js standalone output | + > **Mac Docker Desktop note**: if amd64 builds fail with `Input/output error` > during `apt-get install`, enable **Settings → General → Use Rosetta for x86/amd64 > emulation** (not QEMU). QEMU has known I/O stability issues on macOS; Rosetta diff --git a/scripts/publish-images.sh b/scripts/publish-images.sh new file mode 100755 index 0000000..c48b98f --- /dev/null +++ b/scripts/publish-images.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# One-command publish of all 3 claudemesh images to ghcr.io/alezmad. +# +# Usage: +# GHCR_TOKEN=ghp_xxx ./scripts/publish-images.sh [TAG] +# GHCR_TOKEN=ghp_xxx ./scripts/publish-images.sh 0.1.0 +# ./scripts/publish-images.sh 0.1.0 --dry-run # no login, no push +# +# Produces (all multi-arch: linux/amd64 + linux/arm64): +# ghcr.io/alezmad/claudemesh-broker: + :latest +# ghcr.io/alezmad/claudemesh-web: + :latest +# ghcr.io/alezmad/claudemesh-migrate: + :latest +# +# Prereqs: +# - docker buildx (Docker Desktop on Mac ships with it) +# - GHCR_TOKEN env var: a GitHub personal access token with `write:packages` +# scope. Create at https://github.com/settings/tokens +# +# Image sizes after the pnpm deploy trim (arm64): +# claudemesh-broker ~341 MB +# claudemesh-migrate ~653 MB +# claudemesh-web (next.js standalone, ~250 MB) + +set -euo pipefail + +TAG="${1:-latest}" +DRY_RUN=false + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=true ;; + esac +done + +REGISTRY="ghcr.io/alezmad" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if $DRY_RUN; then + echo "=== DRY RUN — no login, no push ===" + echo "" + echo "Would run:" + echo " echo \$GHCR_TOKEN | docker login ghcr.io -u alezmad --password-stdin" + echo " ${SCRIPT_DIR}/build-multiarch.sh ${REGISTRY} ${TAG}" + echo "" + echo "Images that would be published:" + echo " ${REGISTRY}/claudemesh-broker:${TAG} + :latest" + echo " ${REGISTRY}/claudemesh-web:${TAG} + :latest" + echo " ${REGISTRY}/claudemesh-migrate:${TAG} + :latest" + echo " (platforms: linux/amd64, linux/arm64)" + exit 0 +fi + +if [[ -z "${GHCR_TOKEN:-}" ]]; then + echo "error: GHCR_TOKEN env var is required." >&2 + echo "Create a GitHub PAT with 'write:packages' scope at" >&2 + echo " https://github.com/settings/tokens" >&2 + echo "Then re-run: GHCR_TOKEN=ghp_xxx $0 ${TAG}" >&2 + exit 1 +fi + +echo "→ logging in to ghcr.io as alezmad" +echo "$GHCR_TOKEN" | docker login ghcr.io -u alezmad --password-stdin + +echo "→ building + pushing ${REGISTRY}/claudemesh-{broker,web,migrate}:${TAG}" +"${SCRIPT_DIR}/build-multiarch.sh" "${REGISTRY}" "${TAG}" + +echo "" +echo "✓ published. pull with:" +echo " docker pull ${REGISTRY}/claudemesh-broker:${TAG}"