chore: add provider-agnostic bootstrap (#1377)

This commit is contained in:
Carlos Florêncio
2026-06-14 22:05:49 +01:00
committed by GitHub
parent 828385be2a
commit d6cf4a1acc
6 changed files with 273 additions and 20 deletions
+190
View File
@@ -0,0 +1,190 @@
#!/usr/bin/env bash
# bootstrap-dev-env - provider-agnostic Kandev development environment setup.
#
# Cloud executor prepare scripts should handle provider concerns first:
# authentication, clone/checkout, workspace placement, and agentctl startup.
# After cloning, call this script from the repo root to install the Kandev
# toolchain and dependencies consistently across Sprites, Daytona, Modal,
# Codespaces, local VMs, and similar environments.
#
# Usage:
# scripts/bootstrap-dev-env [options]
#
# Options:
# --with-e2e Install Playwright browser/system deps for E2E
# --without-hooks Skip pre-commit hook wiring
# --without-node-modules Skip pnpm install
# --without-os-packages Skip best-effort OS package installation
# --without-mise-install Require mise to already be installed
# --provider NAME Record caller/provider name in logs only
# -h, --help Show this help
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
WITH_E2E=0
WITH_HOOKS=1
WITH_NODE_MODULES=1
WITH_OS_PACKAGES=1
WITH_MISE_INSTALL=1
PROVIDER="generic"
usage() {
awk 'NR > 1 { if ($0 !~ /^#/) exit; sub(/^# ?/, ""); print }' "$0"
exit "${1:-2}"
}
while [[ $# -gt 0 ]]; do
case "$1" in
--with-e2e) WITH_E2E=1; shift ;;
--without-hooks) WITH_HOOKS=0; shift ;;
--without-node-modules) WITH_NODE_MODULES=0; shift ;;
--without-os-packages) WITH_OS_PACKAGES=0; shift ;;
--without-mise-install) WITH_MISE_INSTALL=0; shift ;;
--provider) PROVIDER="${2:?--provider requires a value}"; shift 2 ;;
-h|--help) usage 0 ;;
*) echo "bootstrap-dev-env: unknown argument '$1'" >&2; usage 2 ;;
esac
done
log() { printf '[bootstrap:%s] %s\n' "$PROVIDER" "$*" >&2; }
warn() { printf '[bootstrap:%s] warning: %s\n' "$PROVIDER" "$*" >&2; }
die() { printf '[bootstrap:%s] error: %s\n' "$PROVIDER" "$*" >&2; exit 1; }
run_privileged() {
if [[ "${EUID:-$(id -u)}" -eq 0 ]]; then
"$@"
elif command -v sudo >/dev/null 2>&1; then
sudo "$@"
else
return 127
fi
}
install_os_packages() {
[[ "$WITH_OS_PACKAGES" -eq 1 ]] || { log "skipping OS packages"; return 0; }
if command -v apt-get >/dev/null 2>&1; then
log "installing OS packages with apt-get"
if ! run_privileged apt-get update; then
warn "apt-get requires root/sudo; skipping OS package installation"
return 0
fi
run_privileged env DEBIAN_FRONTEND=noninteractive apt-get install -y \
bash build-essential ca-certificates curl file git gzip lsof make openssh-client \
pipx pkg-config python3 python3-pip rsync sqlite3 tar unzip xz-utils zip \
libsqlite3-dev || warn "apt-get package installation failed; continuing because packages may already be present"
return 0
fi
if command -v dnf >/dev/null 2>&1; then
log "installing OS packages with dnf"
run_privileged dnf install -y \
bash ca-certificates curl file gcc gcc-c++ git gzip lsof make openssh-clients \
pipx pkgconf-pkg-config python3 python3-pip rsync sqlite sqlite-devel tar unzip xz zip \
|| warn "dnf package installation failed; continuing because packages may already be present"
return 0
fi
if command -v apk >/dev/null 2>&1; then
log "installing OS packages with apk"
run_privileged apk add --no-cache \
bash build-base ca-certificates curl file git gzip lsof make openssh-client \
pipx pkgconf python3 py3-pip rsync sqlite sqlite-dev tar unzip xz zip \
|| warn "apk package installation failed; continuing because packages may already be present"
return 0
fi
if command -v brew >/dev/null 2>&1; then
log "installing OS packages with Homebrew"
brew install bash ca-certificates curl file git lsof make openssh pipx pkg-config \
python rsync sqlite unzip xz zip \
|| warn "Homebrew package installation failed; continuing because packages may already be present"
return 0
fi
warn "no supported package manager found; install build tools, sqlite headers, unzip, pipx, and OpenSSH manually if needed"
}
install_mise() {
if command -v mise >/dev/null 2>&1; then
log "mise already installed: $(mise --version 2>/dev/null || true)"
persist_mise_activation
return 0
fi
[[ "$WITH_MISE_INSTALL" -eq 1 ]] || die "mise is not installed and --without-mise-install was passed"
command -v curl >/dev/null 2>&1 || die "curl is required to install mise"
log "installing mise"
tmp_mise_script="$(mktemp)"
trap 'rm -f "$tmp_mise_script"' EXIT
curl -fsSL https://mise.run -o "$tmp_mise_script"
sh "$tmp_mise_script"
export PATH="$HOME/.local/bin:$PATH"
command -v mise >/dev/null 2>&1 || die "mise install finished but mise is not on PATH"
persist_mise_activation
}
persist_mise_activation() {
[[ -n "${HOME:-}" ]] || return 0
local bashrc="$HOME/.bashrc"
touch "$bashrc"
grep -Fqx 'export PATH="$HOME/.local/bin:$PATH"' "$bashrc" 2>/dev/null \
|| printf '\nexport PATH="$HOME/.local/bin:$PATH"\n' >> "$bashrc"
grep -Fqx 'eval "$(mise activate bash)"' "$bashrc" 2>/dev/null \
|| printf 'eval "$(mise activate bash)"\n' >> "$bashrc"
}
activate_mise() {
export PATH="$HOME/.local/bin:$PATH"
cd "$REPO_ROOT"
[[ -f "$REPO_ROOT/mise.toml" ]] || die "missing mise.toml at repo root"
log "trusting mise.toml"
mise trust "$REPO_ROOT/mise.toml" >/dev/null 2>&1 || mise trust >/dev/null
log "installing mise tools"
mise install
log "activating mise environment for bootstrap"
eval "$(mise activate bash)"
}
install_node_modules() {
[[ "$WITH_NODE_MODULES" -eq 1 ]] || { log "skipping pnpm install"; return 0; }
log "installing pnpm workspace dependencies"
cd "$REPO_ROOT/apps"
pnpm install --frozen-lockfile
}
install_hooks() {
[[ "$WITH_HOOKS" -eq 1 ]] || { log "skipping git hook setup"; return 0; }
log "wiring pre-commit hooks"
cd "$REPO_ROOT"
make doctor
}
install_e2e() {
[[ "$WITH_E2E" -eq 1 ]] || { log "skipping Playwright E2E browser setup"; return 0; }
log "installing Playwright Chromium browser/deps"
"$REPO_ROOT/scripts/install-playwright-browsers.sh"
}
main() {
cd "$REPO_ROOT"
log "bootstrapping Kandev development environment at $REPO_ROOT"
install_os_packages
install_mise
activate_mise
install_node_modules
install_hooks
install_e2e
log "bootstrap complete"
}
main