merchant: in-container selfbuild-webui by tag/commit

This commit is contained in:
Hernâni Marques 2026-07-18 14:19:30 +02:00
parent 8de2e4d6c8
commit cad3044c34
No known key found for this signature in database

View file

@ -0,0 +1,197 @@
#!/usr/bin/env bash
# Build taler-merchant-webui SPA *inside* this container and install it.
#
# Usage (as root in taler-hacktivism):
# selfbuild-webui.sh [REF]
# selfbuild-webui.sh v1.6.11
# selfbuild-webui.sh 0e4807845fc06f7c705711974650d67ef30e7919
# WEBUI_REF=master selfbuild-webui.sh
#
# Env:
# WEBUI_REF tag / branch / commit (default: first arg or v1.6.11)
# TTC_GIT default https://git.taler.net/taler-typescript-core.git
# TTC_DIR default /var/taler-src/taler-typescript-core
# SPA_DEST default /usr/share/taler-merchant-webui
# PNPM_VERSION default 10.33.4
# SKIP_NODE_INSTALL 1 = do not apt/npm install node/pnpm
# SKIP_DEPLOY 1 = build only, leave dist/prod in tree
# EXPECT_VERSION if set, die unless dist version.txt matches
#
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
export PATH="/usr/local/bin:/usr/bin:/bin:${HOME}/.local/bin:${PATH:-}"
WEBUI_REF="${WEBUI_REF:-${1:-v1.6.11}}"
TTC_GIT="${TTC_GIT:-https://git.taler.net/taler-typescript-core.git}"
TTC_DIR="${TTC_DIR:-/var/taler-src/taler-typescript-core}"
SPA_DEST="${SPA_DEST:-/usr/share/taler-merchant-webui}"
PNPM_VERSION="${PNPM_VERSION:-10.33.4}"
SKIP_NODE_INSTALL="${SKIP_NODE_INSTALL:-0}"
SKIP_DEPLOY="${SKIP_DEPLOY:-0}"
EXPECT_VERSION="${EXPECT_VERSION:-}"
log() { printf '+ %s\n' "$*"; }
die() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }
[ "$(id -u)" -eq 0 ] || die "run as root in the merchant container"
# ---------------------------------------------------------------------------
# Toolchain: node + pnpm
# ---------------------------------------------------------------------------
ensure_node() {
if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1; then
log "node $(node -v) npm $(npm -v)"
return 0
fi
[ "${SKIP_NODE_INSTALL}" = "1" ] && die "node/npm missing and SKIP_NODE_INSTALL=1"
log "install nodejs + npm via apt"
apt-get update -qq
apt-get install -y --no-install-recommends nodejs npm ca-certificates git \
python3 curl ca-certificates 2>&1 | tail -20
command -v node >/dev/null 2>&1 || die "node still missing after apt"
log "node $(node -v) npm $(npm -v)"
}
ensure_pnpm() {
if command -v pnpm >/dev/null 2>&1; then
log "pnpm $(pnpm -v)"
return 0
fi
[ "${SKIP_NODE_INSTALL}" = "1" ] && die "pnpm missing and SKIP_NODE_INSTALL=1"
log "install pnpm@${PNPM_VERSION} globally"
npm install -g "pnpm@${PNPM_VERSION}" 2>&1 | tail -15
# npm global bin may be /usr/local/bin or under /usr/lib
hash -r 2>/dev/null || true
export PATH="$(npm prefix -g)/bin:${PATH}"
command -v pnpm >/dev/null 2>&1 || die "pnpm still missing after npm install -g"
log "pnpm $(pnpm -v)"
}
# ---------------------------------------------------------------------------
# Source tree at REF
# ---------------------------------------------------------------------------
checkout_ttc() {
mkdir -p /var/taler-src
if [ -d "${TTC_DIR}/.git" ]; then
log "update existing ${TTC_DIR}"
cd "${TTC_DIR}"
git remote set-url origin "${TTC_GIT}" 2>/dev/null \
|| git remote add origin "${TTC_GIT}" || true
git fetch --tags --force origin
else
log "clone ${TTC_GIT}${TTC_DIR}"
rm -rf "${TTC_DIR}"
git clone "${TTC_GIT}" "${TTC_DIR}"
cd "${TTC_DIR}"
fi
log "checkout ${WEBUI_REF}"
# Accept tag, branch, or raw commit
if git rev-parse --verify --quiet "refs/tags/${WEBUI_REF}" >/dev/null; then
git checkout -f "refs/tags/${WEBUI_REF}"
elif git rev-parse --verify --quiet "origin/${WEBUI_REF}" >/dev/null; then
git checkout -f -B "${WEBUI_REF}" "origin/${WEBUI_REF}"
elif git rev-parse --verify --quiet "${WEBUI_REF}" >/dev/null; then
git checkout -f "${WEBUI_REF}"
else
# maybe short hash only available after fetch
git fetch origin "${WEBUI_REF}" 2>/dev/null || true
git checkout -f "${WEBUI_REF}" || die "cannot checkout WEBUI_REF=${WEBUI_REF}"
fi
# assets submodule (needed by build.mjs)
if [ -f .gitmodules ] && grep -q 'taler-assets' .gitmodules 2>/dev/null; then
log "submodule contrib/taler-assets"
git submodule update --init contrib/taler-assets \
|| git submodule update --init --recursive contrib/taler-assets \
|| true
fi
if [ ! -f contrib/taler-assets/svg/logo/qr-logo.svg ]; then
# fallback: shallow clone assets next to known relative url
log "assets missing — try direct clone"
rm -rf contrib/taler-assets
mkdir -p contrib
git clone --depth 1 https://git.taler.net/taler-assets.git contrib/taler-assets \
|| die "taler-assets incomplete"
fi
test -f contrib/taler-assets/svg/logo/qr-logo.svg || die "taler-assets still incomplete"
HEAD_SHORT=$(git rev-parse --short HEAD)
HEAD_FULL=$(git rev-parse HEAD)
PKG_VER=$(python3 -c "import json; print(json.load(open('packages/taler-merchant-webui/package.json'))['version'])")
log "HEAD=${HEAD_SHORT} (${HEAD_FULL})"
log "package.json version=${PKG_VER}"
}
# ---------------------------------------------------------------------------
# Build + install
# ---------------------------------------------------------------------------
build_spa() {
cd "${TTC_DIR}"
log "pnpm install + compile @gnu-taler/taler-merchant-webui"
pnpm install --frozen-lockfile --filter @gnu-taler/taler-merchant-webui...
pnpm run --filter @gnu-taler/taler-merchant-webui... compile
PROD="${TTC_DIR}/packages/taler-merchant-webui/dist/prod"
test -f "${PROD}/index.js" || die "dist/prod/index.js missing"
test -f "${PROD}/version.txt" || die "dist/prod/version.txt missing"
GOT=$(tr -d ' \n\r' <"${PROD}/version.txt")
log "built version.txt=${GOT}"
if [ -n "${EXPECT_VERSION}" ] && [ "${GOT}" != "${EXPECT_VERSION}" ]; then
die "expected version ${EXPECT_VERSION}, got ${GOT}"
fi
# sensible default when building known tag
case "${WEBUI_REF}" in
v1.6.11|1.6.11)
[ "${GOT}" = "1.6.11" ] || die "expected 1.6.11 for ref ${WEBUI_REF}, got ${GOT}"
;;
esac
BUILT_VER="${GOT}"
}
deploy_spa() {
cd "${TTC_DIR}"
PROD="${TTC_DIR}/packages/taler-merchant-webui/dist/prod"
HEAD_SHORT=$(git rev-parse --short HEAD)
ts=$(date +%Y%m%d-%H%M%S)
if [ -d "${SPA_DEST}" ] && [ "$(ls -A "${SPA_DEST}" 2>/dev/null || true)" ]; then
bak="${SPA_DEST}.bak-selfbuild-${ts}"
log "backup ${SPA_DEST}${bak}"
cp -a "${SPA_DEST}" "${bak}"
fi
mkdir -p "${SPA_DEST}"
find "${SPA_DEST}" -mindepth 1 -maxdepth 1 ! -name 'bak-*' -exec rm -rf {} +
log "install SPA → ${SPA_DEST}"
cp -a "${PROD}/." "${SPA_DEST}/"
printf 'selfbuild-%s-%s\n' "${WEBUI_REF}" "${HEAD_SHORT}" >"${SPA_DEST}/version-overlay.txt"
chown -R root:root "${SPA_DEST}"
echo "=== deployed ==="
cat "${SPA_DEST}/version.txt"
echo
cat "${SPA_DEST}/version-overlay.txt"
echo
wc -c "${SPA_DEST}/index.js"
}
# ---------------------------------------------------------------------------
main() {
log "selfbuild-webui REF=${WEBUI_REF}"
ensure_node
ensure_pnpm
checkout_ttc
build_spa
if [ "${SKIP_DEPLOY}" = "1" ]; then
log "SKIP_DEPLOY=1 — left at ${TTC_DIR}/packages/taler-merchant-webui/dist/prod"
else
deploy_spa
fi
log "DONE webui ${WEBUI_REF} → version ${BUILT_VER:-?} @ ${SPA_DEST}"
}
main "$@"