#!/usr/bin/env bash # Build taler-merchant-webui from tag v1.6.11 + taler-merchant from master, # deploy into podman container taler-hacktivism on koopa, restart services. # # Run from clementine (or any host with: git, node/pnpm, ssh koopa, podman on koopa): # ./scripts/taler-merchant/build-deploy-webui-1.6.11-merchant-master.sh # # Env: # KOOPA_SSH=koopa # MERCHANT_CTR=taler-hacktivism # TTC_GIT=git@git.taler.net:taler-typescript-core.git # MERCHANT_GIT=https://git.taler.net/merchant.git # or git@… # WEBUI_TAG=v1.6.11 # MERCHANT_REF=master # SKIP_WEBUI=0 SKIP_MERCHANT=0 SKIP_RESTART=0 # PNPM=$HOME/.local/bin/pnpm # WORK_ROOT=/tmp/taler-selfbuild-$$ # set -euo pipefail KOOPA_SSH="${KOOPA_SSH:-koopa}" MERCHANT_CTR="${MERCHANT_CTR:-taler-hacktivism}" TTC_GIT="${TTC_GIT:-git@git.taler.net:taler-typescript-core.git}" MERCHANT_GIT="${MERCHANT_GIT:-https://git.taler.net/merchant.git}" WEBUI_TAG="${WEBUI_TAG:-v1.6.11}" MERCHANT_REF="${MERCHANT_REF:-master}" SKIP_WEBUI="${SKIP_WEBUI:-0}" SKIP_MERCHANT="${SKIP_MERCHANT:-0}" SKIP_RESTART="${SKIP_RESTART:-0}" PNPM="${PNPM:-$HOME/.local/bin/pnpm}" WORK_ROOT="${WORK_ROOT:-/tmp/taler-selfbuild-$$}" SPA_DIR="${WORK_ROOT}/spa-prod" TTC_DIR="${WORK_ROOT}/taler-typescript-core" export PATH="${HOME}/.local/bin:${PATH}" log() { printf '+ %s\n' "$*"; } die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "missing command: $1"; } ssh_koopa() { ssh -o BatchMode=yes -o ConnectTimeout=15 "${KOOPA_SSH}" "$@" } ctr_root() { ssh_koopa podman exec -u root "${MERCHANT_CTR}" bash -c "$*" } log "work root: ${WORK_ROOT}" mkdir -p "${WORK_ROOT}" need git need ssh need tar need curl # --------------------------------------------------------------------------- # 1) WebUI from tag # --------------------------------------------------------------------------- if [ "${SKIP_WEBUI}" != "1" ]; then need node if [ ! -x "${PNPM}" ]; then log "installing pnpm to ~/.local …" npm install -g pnpm@10.33.4 --prefix "${HOME}/.local" fi need pnpm || [ -x "${PNPM}" ] PNPM_BIN=$(command -v pnpm || echo "${PNPM}") log "clone ${TTC_GIT} @ ${WEBUI_TAG} (full clone, not worktree — build.mjs needs real .git)" rm -rf "${TTC_DIR}" git clone --branch "${WEBUI_TAG}" --depth 1 "${TTC_GIT}" "${TTC_DIR}" cd "${TTC_DIR}" git submodule update --init contrib/taler-assets test -f contrib/taler-assets/svg/logo/qr-logo.svg || die "taler-assets submodule incomplete" ver=$(python3 -c "import json; print(json.load(open('packages/taler-merchant-webui/package.json'))['version'])") log "package.json version=${ver} HEAD=$(git rev-parse --short HEAD)" log "pnpm install + compile merchant-webui …" "${PNPM_BIN}" install --frozen-lockfile --filter @gnu-taler/taler-merchant-webui... "${PNPM_BIN}" run --filter @gnu-taler/taler-merchant-webui... compile test -f packages/taler-merchant-webui/dist/prod/index.js || die "dist/prod/index.js missing" test -f packages/taler-merchant-webui/dist/prod/version.txt || die "version.txt missing" got=$(tr -d '\n' < packages/taler-merchant-webui/dist/prod/version.txt) log "built SPA version.txt=${got}" # expect 1.6.11 for default tag case "${WEBUI_TAG}" in v1.6.11|1.6.11) [ "${got}" = "1.6.11" ] || die "expected version 1.6.11, got ${got}" ;; esac rm -rf "${SPA_DIR}" mkdir -p "${SPA_DIR}" cp -a packages/taler-merchant-webui/dist/prod/. "${SPA_DIR}/" printf 'selfbuild-%s-%s\n' "${WEBUI_TAG}" "$(git rev-parse --short HEAD)" >"${SPA_DIR}/version-overlay.txt" log "deploy SPA into ${MERCHANT_CTR}:/usr/share/taler-merchant-webui" ts=$(date +%Y%m%d-%H%M%S) ctr_root " set -e if [ -d /usr/share/taler-merchant-webui ]; then cp -a /usr/share/taler-merchant-webui /usr/share/taler-merchant-webui.bak-selfbuild-${ts} fi mkdir -p /usr/share/taler-merchant-webui # clear previous SPA files (keep directory) find /usr/share/taler-merchant-webui -mindepth 1 -maxdepth 1 ! -name 'bak-*' -exec rm -rf {} + " tar -C "${SPA_DIR}" -czf - . | ssh_koopa "podman exec -i -u root ${MERCHANT_CTR} bash -c ' set -e cd /usr/share/taler-merchant-webui tar -xzf - chown -R root:root /usr/share/taler-merchant-webui echo deployed: cat version.txt cat version-overlay.txt wc -c index.js '" log "webui deploy done" else log "SKIP_WEBUI=1" fi # --------------------------------------------------------------------------- # 2) Merchant backend from master (build inside container) # --------------------------------------------------------------------------- if [ "${SKIP_MERCHANT}" != "1" ]; then log "build taler-merchant ${MERCHANT_REF} inside ${MERCHANT_CTR}" # Install build deps if missing; update /var/taler-src/merchant; bootstrap; make install ssh_koopa "podman exec -u root ${MERCHANT_CTR} bash -s" <&1 | tail -30 || true # exchange headers sometimes via package names that differ apt-get install -y --no-install-recommends libtalerutil-dev 2>/dev/null || true echo '=== source tree ===' mkdir -p /var/taler-src if [ -d "\$SRC/.git" ]; then cd "\$SRC" git remote set-url origin "\$GIT_URL" 2>/dev/null || git remote add origin "\$GIT_URL" || true git fetch --tags origin git checkout "\$REF" git pull --ff-only origin "\$REF" || git reset --hard "origin/\$REF" else rm -rf "\$SRC" git clone "\$GIT_URL" "\$SRC" cd "\$SRC" git checkout "\$REF" fi # submodules if any git submodule update --init --recursive 2>/dev/null || true echo "merchant HEAD=\$(git rev-parse --short HEAD) \$(git log -1 --oneline)" echo '=== bootstrap / configure / make ===' if [ ! -x configure ]; then ./bootstrap fi # Prefer /usr prefix to replace package binaries ./configure --prefix=/usr --disable-doc 2>&1 | tail -40 make -j"\$(nproc)" 2>&1 | tail -50 make install 2>&1 | tail -30 echo '=== installed httpd ===' ls -la /usr/bin/taler-merchant-httpd taler-merchant-httpd --help 2>&1 | head -5 || true # record build id git rev-parse HEAD > /usr/share/taler-merchant/SELFBUILD_MERCHANT_HEAD 2>/dev/null \\ || mkdir -p /usr/share/taler-merchant && git rev-parse HEAD > /usr/share/taler-merchant/SELFBUILD_MERCHANT_HEAD echo "SELFBUILD_MERCHANT_HEAD=\$(cat /usr/share/taler-merchant/SELFBUILD_MERCHANT_HEAD)" REMOTE log "merchant build/install done" else log "SKIP_MERCHANT=1" fi # --------------------------------------------------------------------------- # 3) Restart + health # --------------------------------------------------------------------------- if [ "${SKIP_RESTART}" != "1" ]; then log "restart merchant services" ssh_koopa "podman exec -u root ${MERCHANT_CTR} bash -c ' set -e if id taler-merchant-httpd >/dev/null 2>&1; then runuser -u taler-merchant-httpd -- taler-merchant-dbinit 2>&1 | tail -15 || true fi runuser -u taler-merchant-httpd -- /usr/local/bin/start_merchant.sh --restart '" log "smoke" ssh_koopa 'curl -skS -m 8 -o /dev/null -w "merchant_local %{http_code}\n" https://127.0.0.1:9010/config || true' curl -skS -m 12 -o /dev/null -w "merchant_public %{http_code}\n" https://taler.hacktivism.ch/config || true curl -skS -m 12 -o /dev/null -w "webui %{http_code}\n" https://taler.hacktivism.ch/webui/ || true pubver=$(curl -skS -m 12 https://taler.hacktivism.ch/webui/version.txt 2>/dev/null || true) pubov=$(curl -skS -m 12 https://taler.hacktivism.ch/webui/version-overlay.txt 2>/dev/null || true) log "public version.txt=${pubver}" log "public version-overlay.txt=${pubov}" else log "SKIP_RESTART=1" fi log "DONE" log " webui: tag ${WEBUI_TAG} → container /usr/share/taler-merchant-webui" log " merchant: ${MERCHANT_REF} → /usr/bin/taler-merchant-*" log " work left at ${WORK_ROOT} (delete when satisfied)"