gitmote

gitmote / scripts / e2e-local.sh  ·  history  ·  branches

3209 bytes · raw

#!/usr/bin/env bash
# End-to-end proof that gitmote hosts itself: bring up MinIO + a gitmote
# container, bootstrap an admin/token/repo, push this working tree to it, clone
# it back, and assert the clone is byte-for-byte the pushed history. Then
# force-recreate the container (wiping the ephemeral cache) and clone again to
# prove durability comes from the object store + persisted refs, not local disk.
set -euo pipefail

DC="docker compose"
ROOT="$(git rev-parse --show-toplevel)"
# Fall back to a name when HEAD is detached (CI checkouts are), since the remote
# branch we host under is our own choice anyway.
BRANCH="$(git -C "$ROOT" symbolic-ref --quiet --short HEAD || echo master)"
PUSHED="$(git -C "$ROOT" rev-parse HEAD)"

# Fail fast instead of prompting; ignore any host credential helper.
export GIT_TERMINAL_PROMPT=0
GITC=(git -c credential.helper= -c http.postBuffer=524288000)

CLONES=()
cleanup() {
  local code=$?
  echo "--- tearing down ---"
  ( cd "$ROOT" && $DC down -v --remove-orphans ) || true
  for d in "${CLONES[@]:-}"; do [ -n "$d" ] && rm -rf "$d"; done
  exit $code
}
trap cleanup EXIT

fail() { echo "E2E FAIL: $*" >&2; exit 1; }

wait_healthz() {
  echo "--- waiting for gitmote /healthz ---"
  for _ in $(seq 1 60); do
    if curl -fsS http://localhost:8080/healthz >/dev/null 2>&1; then return 0; fi
    sleep 1
  done
  ( cd "$ROOT" && $DC logs gitmote ) || true
  fail "gitmote did not become healthy"
}

# assert_clone <label>: clone the repo fresh and check HEAD, fsck, and tree.
assert_clone() {
  local label="$1" clone
  clone="$(mktemp -d)"
  CLONES+=("$clone")
  echo "--- clone ($label) ---"
  "${GITC[@]}" clone "$REPO_URL" "$clone" || fail "$label: clone failed"

  local cloned
  cloned="$(git -C "$clone" rev-parse HEAD)"
  [ "$cloned" = "$PUSHED" ] || fail "$label: HEAD $cloned != pushed $PUSHED"

  git -C "$clone" fsck --full --strict || fail "$label: fsck not clean"

  diff <(git -C "$ROOT" ls-tree -r "$PUSHED") <(git -C "$clone" ls-tree -r HEAD) \
    || fail "$label: file tree differs from pushed commit"
  echo "--- clone ($label) OK: HEAD=$cloned, fsck clean, tree identical ---"
}

cd "$ROOT"

echo "--- building gitmote image ---"
$DC build gitmote

echo "--- starting minio + creating bucket ---"
$DC up -d minio
$DC run --rm mc

echo "--- bootstrap (one-shot, writes admin/token/repo to the metadata volume) ---"
BOOT="$($DC run --rm -T gitmote bootstrap -handle admin -repo gitmote -default-branch "$BRANCH")"
TOKEN="$(printf '%s\n' "$BOOT" | grep -oE 'gmt_[0-9a-f]+\.[0-9a-f]+' | head -1)"
[ -n "$TOKEN" ] || { printf '%s\n' "$BOOT"; fail "no token in bootstrap output"; }

REPO_URL="http://admin:${TOKEN}@localhost:8080/gitmote"

echo "--- starting gitmote server ---"
$DC up -d gitmote
wait_healthz

echo "--- push this working tree ($BRANCH @ $PUSHED) ---"
"${GITC[@]}" -C "$ROOT" push "$REPO_URL" "HEAD:refs/heads/${BRANCH}" || fail "push failed"

assert_clone "initial"

echo "--- force-recreate container (wipes ephemeral cache; refs+objects persist) ---"
$DC up -d --force-recreate --no-deps gitmote
wait_healthz
assert_clone "after-restart"

echo "E2E PASS: gitmote hosted itself — push, clone, and restart-durability all green."