|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Integration smoke test: pack the CLI, install it globally, and exercise |
| 3 | +# offline commands to confirm a fresh install actually works end-to-end. |
| 4 | +# |
| 5 | +# Required tools: bun (always); node + npm (only when INTEGRATION_RUNTIME=npm). |
| 6 | +# Configure via env: |
| 7 | +# INTEGRATION_RUNTIME bun | npm (default: bun) |
| 8 | + |
| 9 | +set -euo pipefail |
| 10 | + |
| 11 | +RUNTIME="${INTEGRATION_RUNTIME:-bun}" |
| 12 | +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
| 13 | +WORK_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t routstr-it)" |
| 14 | +INSTALL_PREFIX="${WORK_DIR}/prefix" |
| 15 | +PACK_DIR="${WORK_DIR}/pack" |
| 16 | +mkdir -p "${INSTALL_PREFIX}" "${PACK_DIR}" |
| 17 | + |
| 18 | +cleanup() { |
| 19 | + rm -rf "${WORK_DIR}" || true |
| 20 | +} |
| 21 | +trap cleanup EXIT |
| 22 | + |
| 23 | +log() { printf '\n\033[1;36m==>\033[0m %s\n' "$*"; } |
| 24 | +fail() { printf '\n\033[1;31mFAIL:\033[0m %s\n' "$*" >&2; exit 1; } |
| 25 | + |
| 26 | +cd "${REPO_ROOT}" |
| 27 | + |
| 28 | +[ -f dist/index.js ] || fail "dist/index.js missing — run 'bun run build' first." |
| 29 | + |
| 30 | +log "Packing CLI tarball" |
| 31 | +# `npm pack` is available on both runtimes via the bun-shipped node, but we |
| 32 | +# prefer the runtime under test so the tarball mirrors what users would publish. |
| 33 | +case "${RUNTIME}" in |
| 34 | + bun) |
| 35 | + if ! command -v bun >/dev/null 2>&1; then fail "bun not on PATH"; fi |
| 36 | + ;; |
| 37 | + npm) |
| 38 | + if ! command -v npm >/dev/null 2>&1; then fail "npm not on PATH"; fi |
| 39 | + ;; |
| 40 | + *) |
| 41 | + fail "Unknown INTEGRATION_RUNTIME='${RUNTIME}' (use bun or npm)" |
| 42 | + ;; |
| 43 | +esac |
| 44 | + |
| 45 | +# npm pack is the lingua franca for tarball creation; both runtimes consume it. |
| 46 | +TARBALL=$(cd "${PACK_DIR}" && npm pack "${REPO_ROOT}" --silent | tail -n 1) |
| 47 | +TARBALL_PATH="${PACK_DIR}/${TARBALL}" |
| 48 | +[ -f "${TARBALL_PATH}" ] || fail "Tarball not produced at ${TARBALL_PATH}" |
| 49 | +log "Created tarball: ${TARBALL_PATH}" |
| 50 | + |
| 51 | +log "Installing globally via ${RUNTIME}" |
| 52 | +case "${RUNTIME}" in |
| 53 | + bun) |
| 54 | + # bun add -g installs into ~/.bun/install/global; override with BUN_INSTALL. |
| 55 | + export BUN_INSTALL="${INSTALL_PREFIX}" |
| 56 | + export PATH="${INSTALL_PREFIX}/bin:${PATH}" |
| 57 | + bun add -g "${TARBALL_PATH}" |
| 58 | + ;; |
| 59 | + npm) |
| 60 | + # npm honors --prefix for non-root global installs. |
| 61 | + export PATH="${INSTALL_PREFIX}/bin:${PATH}" |
| 62 | + npm install -g --prefix "${INSTALL_PREFIX}" "${TARBALL_PATH}" |
| 63 | + ;; |
| 64 | +esac |
| 65 | + |
| 66 | +command -v routstr >/dev/null 2>&1 || fail "'routstr' binary not on PATH after install" |
| 67 | +log "Installed at: $(command -v routstr)" |
| 68 | + |
| 69 | +run_check() { |
| 70 | + local name="$1"; shift |
| 71 | + log "Smoke: ${name}" |
| 72 | + if ! "$@" >/tmp/routstr-it.out 2>&1; then |
| 73 | + cat /tmp/routstr-it.out |
| 74 | + fail "command failed: ${name}" |
| 75 | + fi |
| 76 | +} |
| 77 | + |
| 78 | +assert_contains() { |
| 79 | + local needle="$1" file="$2" |
| 80 | + grep -q -- "${needle}" "${file}" || { |
| 81 | + cat "${file}" |
| 82 | + fail "expected output to contain: ${needle}" |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +# --- Offline commands: do not require a running Routstr node. --- |
| 87 | + |
| 88 | +run_check "routstr --version" routstr --version |
| 89 | +assert_contains "0." /tmp/routstr-it.out |
| 90 | + |
| 91 | +run_check "routstr --help" routstr --help |
| 92 | +assert_contains "routstr" /tmp/routstr-it.out |
| 93 | +assert_contains "instruct" /tmp/routstr-it.out |
| 94 | + |
| 95 | +run_check "routstr schema" routstr schema |
| 96 | +assert_contains "\"name\"" /tmp/routstr-it.out |
| 97 | + |
| 98 | +run_check "routstr instruct" routstr instruct |
| 99 | +assert_contains "routstr" /tmp/routstr-it.out |
| 100 | + |
| 101 | +run_check "routstr instruct --format json" routstr instruct --format json |
| 102 | +# JSON output must parse. |
| 103 | +node -e "JSON.parse(require('fs').readFileSync('/tmp/routstr-it.out','utf8'))" \ |
| 104 | + || fail "instruct --format json produced invalid JSON" |
| 105 | + |
| 106 | +# init --show is safe even when no config exists. |
| 107 | +run_check "routstr init --show" routstr init --show |
| 108 | + |
| 109 | +log "All integration smoke checks passed (${RUNTIME})" |
0 commit comments