better-argo-tunnels/ship.sh

171 lines
5.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# Do NOT add docker login or gh auth token here. A prior gh-based login overwrote good GHCR
# credentials and pushes failed with permission_denied / wrong scopes; compose push works when
# Docker keeps the PAT/credential helper the user already configured.
#
# Fixed pipeline (order is fixed):
# 1. git add -A
# 2. git commit (or --allow-empty if nothing staged)
# 3. GIT_COMMIT → Docker --build-arg (baked into binaries)
# 4. buildx --push per arch + imagetools manifest (server + client) — uses Dockers existing ghcr auth (no docker login here)
# 5. git push — always
#
# Configuration (use your machine / repo — no hardcoded owner or registry):
# - Remote to parse for ghcr.io/owner/repo: git config ship.remote <name> (default: github)
# - Optional full registry base (no tag): git config ship.registryBase ghcr.io/org/image
# - Image tags: git config ship.tagServer / ship.tagClient
# - Platforms (comma-separated): git config ship.platforms
# - Buildx builder: git config ship.buildxBuilder (default: orbstack if present, else default)
#
# The push remote URL must be github.com (ssh or https). Owner/repo set GHCR path unless ship.registryBase is set.
#
# Usage: ./ship.sh <commit message>
set -euo pipefail
if [[ $# -lt 1 ]] || [[ -z "${1// }" ]]; then
echo "usage: $0 <commit message>" >&2
exit 1
fi
COMMIT_MSG="$*"
ROOT="$(cd "$(dirname "$0")" && pwd)"
cd "$ROOT"
for cmd in git docker; do
command -v "$cmd" >/dev/null 2>&1 || {
echo "ship: fatal: missing required command: $cmd" >&2
exit 1
}
done
if ! docker buildx version >/dev/null 2>&1; then
echo "ship: fatal: docker buildx not available" >&2
exit 1
fi
BRANCH="$(git branch --show-current)"
if [[ -z "$BRANCH" ]]; then
echo "ship: fatal: detached HEAD" >&2
exit 1
fi
GIT_REMOTE="$(git config ship.remote 2>/dev/null)" || true
GIT_REMOTE="${GIT_REMOTE:-github}"
if ! REMOTE_URL="$(git remote get-url "$GIT_REMOTE" 2>/dev/null)"; then
echo "ship: fatal: git remote '$GIT_REMOTE' not found (set: git config ship.remote <name>)" >&2
exit 1
fi
REMOTE_OWNER=""
REMOTE_REPO=""
if [[ "$REMOTE_URL" =~ ^git@github\.com:([^/]+)/(.+)$ ]]; then
REMOTE_OWNER="${BASH_REMATCH[1]}"
REMOTE_REPO="${BASH_REMATCH[2]%.git}"
elif [[ "$REMOTE_URL" =~ ^https://github\.com/([^/]+)/([^/?#]+) ]]; then
REMOTE_OWNER="${BASH_REMATCH[1]}"
REMOTE_REPO="${BASH_REMATCH[2]%.git}"
else
echo "ship: fatal: remote '$GIT_REMOTE' URL is not github.com: $REMOTE_URL" >&2
exit 1
fi
REGISTRY_BASE="$(git config ship.registryBase 2>/dev/null)" || true
if [[ -z "$REGISTRY_BASE" ]]; then
o_lc="$(echo "$REMOTE_OWNER" | tr '[:upper:]' '[:lower:]')"
r_lc="$(echo "$REMOTE_REPO" | tr '[:upper:]' '[:lower:]')"
REGISTRY_BASE="ghcr.io/${o_lc}/${r_lc}"
fi
REGISTRY_BASE="${REGISTRY_BASE%/}"
TAG_SERVER="$(git config ship.tagServer 2>/dev/null)" || true
TAG_SERVER="${TAG_SERVER:-production}"
TAG_CLIENT="$(git config ship.tagClient 2>/dev/null)" || true
TAG_CLIENT="${TAG_CLIENT:-client-production}"
PLATFORMS="$(git config ship.platforms 2>/dev/null)" || true
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
BUILDER_OVERRIDE="$(git config ship.buildxBuilder 2>/dev/null)" || true
echo "==> ship: remote=$GIT_REMOTE ($REMOTE_OWNER/$REMOTE_REPO)"
echo "==> ship: registry=$REGISTRY_BASE tags=$TAG_SERVER $TAG_CLIENT"
echo "==> ship: platforms=$PLATFORMS"
echo "==> [1/5] git add -A"
git add -A
echo "==> [2/5] git commit"
if git diff --cached --quiet; then
git commit --allow-empty -m "$COMMIT_MSG"
else
git commit -m "$COMMIT_MSG"
fi
GIT_COMMIT="$(git rev-parse HEAD)"
BA=(--build-arg "GIT_COMMIT=${GIT_COMMIT}")
echo "==> GIT_COMMIT=${GIT_COMMIT}"
pick_builder() {
if [[ -n "$BUILDER_OVERRIDE" ]]; then
echo "$BUILDER_OVERRIDE"
return
fi
if docker buildx inspect orbstack >/dev/null 2>&1; then
echo "orbstack"
else
echo "default"
fi
}
platform_slug() {
local p="${1// /}"
p="${p#linux/}"
echo "${p//\//-}"
}
push_multi() {
local target="$1"
local final_tag="$2"
local builder="$3"
local base="${final_tag%:*}"
local name="${final_tag##*:}"
local arch_refs=()
local p slug arch_tag
IFS=',' read -ra plats <<< "$PLATFORMS"
for p in "${plats[@]}"; do
p="${p// /}"
[[ -z "$p" ]] && continue
slug="$(platform_slug "$p")"
arch_tag="${base}:${name}-${slug}"
echo "==> [3/5] docker buildx push ${target} ${p} -> ${arch_tag}"
docker buildx build \
"${BA[@]}" \
--builder "$builder" \
--platform "$p" \
--target "$target" \
-t "$arch_tag" \
--push \
--provenance=false \
"$ROOT"
arch_refs+=("$arch_tag")
done
echo "==> [4/5] imagetools manifest ${final_tag}"
docker buildx imagetools create -t "$final_tag" "${arch_refs[@]}"
}
BUILDER="$(pick_builder)"
echo "==> buildx builder: ${BUILDER}"
SERVER_TAG="${REGISTRY_BASE}:${TAG_SERVER}"
CLIENT_TAG="${REGISTRY_BASE}:${TAG_CLIENT}"
push_multi server "$SERVER_TAG" "$BUILDER"
push_multi client "$CLIENT_TAG" "$BUILDER"
echo "==> [5/5] git push ${GIT_REMOTE} ${BRANCH}"
git push "$GIT_REMOTE" "$BRANCH"
echo "ship: ok commit=${GIT_COMMIT}"
echo "ship: images ${SERVER_TAG} ${CLIENT_TAG}"