feat(dev-env): shell scripts (git-hooks, worktree, deploy, regtest, nav) and smoke test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7960f82494
commit
dbd9e76027
13 changed files with 2496 additions and 0 deletions
284
modules/dev-env/scripts/regtest.sh
Normal file
284
modules/dev-env/scripts/regtest.sh
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
#!/usr/bin/env bash
|
||||
# dev-env: Bitcoin/Lightning regtest docker environment
|
||||
#
|
||||
# Provides:
|
||||
# regtest-start [env|pr:<branch>] [--seed|--keep]
|
||||
# regtest-stop
|
||||
# regtest-status
|
||||
# regtest-logs [service]
|
||||
# regtest-cli # source CLI helpers
|
||||
# regtest # cd to regtest dir
|
||||
#
|
||||
# Ported from ~/dev/.devenv.d/40-regtest.sh. Reads paths from
|
||||
# /etc/dev-env/config.sh. The bitSpire ATM reaches its Lightning
|
||||
# backend through the LNbits nostr-native transport (the nostrrelay
|
||||
# extension) in this same regtest — there is no separate ATM-backend
|
||||
# container to start.
|
||||
#
|
||||
# This is sourced into interactive shells (function definitions) AND
|
||||
# also dropped into the system path as standalone wrapper scripts so
|
||||
# `regtest-start` works from a fresh non-interactive shell.
|
||||
|
||||
# Shared base config loader lives in /etc/dev-env/lib.sh; this module
|
||||
# layers regtest-specific path defaults on top.
|
||||
if [[ -r /etc/dev-env/lib.sh ]]; then
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/dev-env/lib.sh
|
||||
fi
|
||||
|
||||
_devenv_load_config() {
|
||||
_devenv_source_config
|
||||
REGTEST_DIR="${LOCAL_DIR:-$DEV_ROOT/local}/docker/regtest"
|
||||
LNBITS_DIR="${LNBITS_DIR:-$DEV_ROOT/lnbits}"
|
||||
UPSTREAM_PRS_DIR="${UPSTREAM_PRS_DIR:-$DEV_ROOT/upstream-prs}"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Status helpers
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
_regtest_is_running() {
|
||||
docker ps --filter "name=lnbits-lnd-4-1" --format '{{.Names}}' 2>/dev/null \
|
||||
| grep -q lnbits-lnd-4-1
|
||||
}
|
||||
|
||||
_wait_for_lnd4() {
|
||||
local attempts=0
|
||||
echo "Waiting for lnd-4..."
|
||||
while ! docker exec lnbits-lnd-4-1 lncli --network=regtest --rpcserver=lnd-4:10009 getinfo &>/dev/null; do
|
||||
if (( attempts >= 30 )); then
|
||||
echo "lnd-4 failed to start"
|
||||
return 1
|
||||
fi
|
||||
sleep 2
|
||||
((attempts++))
|
||||
done
|
||||
echo "lnd-4 is ready"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Start
|
||||
#-------------------------------------------------------------------------------
|
||||
# Usage: regtest-start [env|pr:<branch>] [--path <dir>] [--seed|--keep]
|
||||
#
|
||||
# env dev|main (worktree under ~/dev/lnbits/<env>)
|
||||
# pr:<branch> ~/dev/upstream-prs/lnbits-<branch>
|
||||
# --path <dir> arbitrary lnbits directory
|
||||
# --seed copy lnbits-seed/ to lnbits/ before starting
|
||||
# --keep keep existing data
|
||||
regtest-start() {
|
||||
_devenv_load_config
|
||||
|
||||
local env="" data_mode="fresh" custom_path=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--seed) data_mode="seed" ;;
|
||||
--keep) data_mode="keep" ;;
|
||||
--path) shift; custom_path="$1" ;;
|
||||
dev|main) env="$1" ;;
|
||||
pr:*)
|
||||
local pr_branch="${1#pr:}"
|
||||
custom_path="$UPSTREAM_PRS_DIR/lnbits-$pr_branch"
|
||||
;;
|
||||
*)
|
||||
cat <<USAGE
|
||||
Unknown argument: $1
|
||||
Usage: regtest-start [dev|main|pr:<branch>] [--path <dir>] [--seed|--keep]
|
||||
|
||||
Environments:
|
||||
dev, main ~/dev/lnbits/<env>
|
||||
pr:<branch> ~/dev/upstream-prs/lnbits-<branch>
|
||||
--path <dir> arbitrary lnbits directory
|
||||
USAGE
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ ! -d "$REGTEST_DIR" ]]; then
|
||||
echo "Regtest environment not found at $REGTEST_DIR"
|
||||
echo "Run dev-env-bootstrap to clone it."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine lnbits source dir
|
||||
local lnbits_path=""
|
||||
if [[ -n "$custom_path" ]]; then
|
||||
lnbits_path="$custom_path"
|
||||
[[ -d "$lnbits_path" ]] || { echo "lnbits dir not found: $lnbits_path"; return 1; }
|
||||
else
|
||||
[[ -z "$env" ]] && env="dev"
|
||||
lnbits_path="$LNBITS_DIR/$env"
|
||||
[[ -d "$lnbits_path" ]] || { echo "lnbits worktree not found: $env"; return 1; }
|
||||
fi
|
||||
|
||||
local lnbits_data="$REGTEST_DIR/data/lnbits"
|
||||
local lnbits_seed="$REGTEST_DIR/data/lnbits-seed"
|
||||
|
||||
case "$data_mode" in
|
||||
fresh)
|
||||
if [[ -d "$lnbits_data" ]] && [[ -n "$(ls -A "$lnbits_data" 2>/dev/null)" ]]; then
|
||||
echo "Existing lnbits data at $lnbits_data"
|
||||
read -r -p "Wipe it? [y/N] " -n 1 REPLY; echo
|
||||
[[ $REPLY =~ ^[Yy]$ ]] || { echo "Aborted."; return 1; }
|
||||
docker run --rm -v "$lnbits_data":/data alpine sh -c "rm -rf /data/* /data/.*" 2>/dev/null || true
|
||||
rmdir "$lnbits_data" 2>/dev/null || true
|
||||
fi
|
||||
mkdir -p "$lnbits_data"
|
||||
;;
|
||||
seed)
|
||||
[[ -d "$lnbits_seed" ]] || { echo "Seed data not found at $lnbits_seed"; return 1; }
|
||||
if [[ -d "$lnbits_data" ]] && [[ -n "$(ls -A "$lnbits_data" 2>/dev/null)" ]]; then
|
||||
read -r -p "Overwrite with seed? [y/N] " -n 1 REPLY; echo
|
||||
[[ $REPLY =~ ^[Yy]$ ]] || { echo "Aborted."; return 1; }
|
||||
docker run --rm -v "$lnbits_data":/data alpine sh -c "rm -rf /data/* /data/.*" 2>/dev/null || true
|
||||
rmdir "$lnbits_data" 2>/dev/null || true
|
||||
fi
|
||||
cp -r "$lnbits_seed" "$lnbits_data"
|
||||
;;
|
||||
keep)
|
||||
mkdir -p "$lnbits_data"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "Starting regtest..."
|
||||
echo " lnbits path: $lnbits_path"
|
||||
echo " data mode: $data_mode"
|
||||
echo ""
|
||||
|
||||
echo "Building lnbits Docker image from $lnbits_path..."
|
||||
docker build -t lnbits/lnbits "$lnbits_path"
|
||||
|
||||
(cd "$REGTEST_DIR" && ./start-regtest)
|
||||
|
||||
cat <<EOF
|
||||
|
||||
Regtest running:
|
||||
LNbits: http://localhost:5001/
|
||||
Mempool: http://localhost:8080/
|
||||
Boltz: http://localhost:9001/
|
||||
|
||||
EOF
|
||||
|
||||
echo "Commands: regtest-stop, regtest-logs, regtest-cli, regtest-status"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Stop
|
||||
#-------------------------------------------------------------------------------
|
||||
regtest-stop() {
|
||||
_devenv_load_config
|
||||
|
||||
if [[ ! -d "$REGTEST_DIR" ]]; then
|
||||
echo "Regtest environment not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Stopping regtest environment..."
|
||||
(cd "$REGTEST_DIR"
|
||||
# shellcheck disable=SC1091
|
||||
source ./docker-scripts.sh
|
||||
docker compose down -v)
|
||||
echo "Regtest stopped"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Status / logs / CLI
|
||||
#-------------------------------------------------------------------------------
|
||||
regtest-status() {
|
||||
_devenv_load_config
|
||||
|
||||
echo "=== Shared Regtest Environment ==="
|
||||
if _regtest_is_running; then
|
||||
echo "Status: RUNNING"
|
||||
echo ""
|
||||
docker ps --filter "name=lnbits-" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | head -15
|
||||
|
||||
local balance
|
||||
balance="$(docker exec lnbits-lnd-4-1 lncli --network=regtest walletbalance 2>/dev/null \
|
||||
| grep -oP '"total_balance":\s*"\K[0-9]+' || echo 0)"
|
||||
echo ""
|
||||
echo "lnd-4 balance: $balance sats"
|
||||
else
|
||||
echo "Status: STOPPED"
|
||||
echo "Start with: regtest-start"
|
||||
fi
|
||||
}
|
||||
|
||||
regtest-logs() {
|
||||
_devenv_load_config
|
||||
local service="${1:-}"
|
||||
[[ -d "$REGTEST_DIR" ]] || { echo "Regtest not found"; return 1; }
|
||||
if [[ -n "$service" ]]; then
|
||||
(cd "$REGTEST_DIR" && docker compose logs -f "$service")
|
||||
else
|
||||
(cd "$REGTEST_DIR" && docker compose logs -f)
|
||||
fi
|
||||
}
|
||||
|
||||
regtest-cli() {
|
||||
_devenv_load_config
|
||||
[[ -f "$REGTEST_DIR/docker-scripts.sh" ]] || { echo "docker-scripts.sh missing"; return 1; }
|
||||
echo "Sourcing regtest CLI helpers..."
|
||||
# shellcheck disable=SC1091
|
||||
source "$REGTEST_DIR/docker-scripts.sh"
|
||||
cat <<EOF
|
||||
|
||||
Available commands:
|
||||
bitcoin-cli-sim Bitcoin Core CLI
|
||||
lncli-sim <1-4> LND node CLI
|
||||
lightning-cli-sim <1-3> C-Lightning node CLI
|
||||
boltzcli-sim Boltz client CLI
|
||||
elements-cli-sim Elements/Liquid CLI
|
||||
|
||||
Examples:
|
||||
bitcoin-cli-sim -generate 1
|
||||
lncli-sim 1 getinfo
|
||||
EOF
|
||||
}
|
||||
|
||||
regtest() {
|
||||
_devenv_load_config
|
||||
[[ -d "$REGTEST_DIR" ]] && cd "$REGTEST_DIR" || { echo "Regtest not found at $REGTEST_DIR"; return 1; }
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Rebuild / restart the lnbits service (docker-compose.dev.yml workflow)
|
||||
#-------------------------------------------------------------------------------
|
||||
# regtest-lnbits-rebuild build (cached) + recreate the lnbits container
|
||||
# regtest-lnbits-rebuild --clean build --no-cache + recreate (truly fresh image)
|
||||
# regtest-lnbits-restart restart the container without rebuilding
|
||||
#
|
||||
# The cached build is the happy path: docker invalidates the source COPY layer
|
||||
# when LNBITS_SRC content changes, so most rebuilds are fast. Use --clean when
|
||||
# you've been mucking with the image itself.
|
||||
|
||||
_regtest_lnbits_compose_file() {
|
||||
echo "$REGTEST_DIR/docker-compose.dev.yml"
|
||||
}
|
||||
|
||||
regtest-lnbits-rebuild() {
|
||||
_devenv_load_config
|
||||
local compose_file build_args=()
|
||||
compose_file="$(_regtest_lnbits_compose_file)"
|
||||
[[ -f "$compose_file" ]] || { echo "Compose file not found: $compose_file"; return 1; }
|
||||
|
||||
if [[ "${1:-}" == "--clean" ]]; then
|
||||
build_args+=(--no-cache)
|
||||
fi
|
||||
|
||||
(cd "$REGTEST_DIR" \
|
||||
&& docker compose -f "$compose_file" build "${build_args[@]}" lnbits \
|
||||
&& docker compose -f "$compose_file" up -d --force-recreate lnbits)
|
||||
}
|
||||
|
||||
regtest-lnbits-restart() {
|
||||
_devenv_load_config
|
||||
local compose_file
|
||||
compose_file="$(_regtest_lnbits_compose_file)"
|
||||
[[ -f "$compose_file" ]] || { echo "Compose file not found: $compose_file"; return 1; }
|
||||
docker compose -f "$compose_file" restart lnbits
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue