docs(setup): add Debian 13 dev-VM setup procedure + scripts + devcontainer
CI / commits (pull_request) Successful in 2m52s
CI / check (pull_request) Successful in 3m3s
CI / scan (pull_request) Successful in 3m11s
CI / a11y (pull_request) Successful in 3m5s
Docs site / build (pull_request) Successful in 3m10s
CI / perf (pull_request) Successful in 6m53s
CI / commits (pull_request) Successful in 2m52s
CI / check (pull_request) Successful in 3m3s
CI / scan (pull_request) Successful in 3m11s
CI / a11y (pull_request) Successful in 3m5s
Docs site / build (pull_request) Successful in 3m10s
CI / perf (pull_request) Successful in 6m53s
New procedure in docs/setup/01-dev-debian-vm-setup.md targeting the new dev VM (10.100.201.21, Debian 13) that replaces the WSL workflow. The existing setup files are renumbered (01->02, 02->03, 03->04) to free prefix 01 for the default flow. 10 modular idempotent scripts under docs/setup/scripts/ install the stack: zsh + Oh My Zsh + Powerlevel10k + plugins, modern CLI tooling (bat, eza, fd-find, ripgrep, fzf, zoxide, ncdu, keychain + dev extras), nvm + Node from .nvmrc + corepack + pnpm, Docker CE + compose plugin, inotify watches + swap + hostname tuning, best-effort UFW + sshd hardening that probes-before-applying, and notes/aliases.zsh + notes/gitconfig.txt installation. A systemd template (apf-portal-infra@.service) auto-starts the local dev infra stack at boot per user. .devcontainer/ ships a VSCode Dev Container spec pinning Node 24 and attaching to the host's apf-portal-dev Compose network so postgres / redis / otel resolve by DNS from inside the container. initializeCommand fails fast if the infra hasn't been brought up yet. CLAUDE.md Environment conventions documents the two envs (local + development) plus the hybrid sub-mode (workstation IDE + VM infra via SSH LocalForward) and the two IDE flows (Remote-SSH + Devcontainer). Adjacent follow-ups (not in this PR): preview infra on the GitLab VM (10.100.201.10), GitLab Runner migration alongside the Gitea -> GitLab cutover, private dotfiles repo.
This commit is contained in:
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared helpers for docs/setup/scripts/*.sh — sourced from each script.
|
||||
# Idempotency utilities + nice logging.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -t 1 ]]; then
|
||||
C_GREEN=$'\033[1;32m'
|
||||
C_YELLOW=$'\033[1;33m'
|
||||
C_RED=$'\033[1;31m'
|
||||
C_BLUE=$'\033[1;34m'
|
||||
C_DIM=$'\033[2m'
|
||||
C_RESET=$'\033[0m'
|
||||
else
|
||||
C_GREEN= C_YELLOW= C_RED= C_BLUE= C_DIM= C_RESET=
|
||||
fi
|
||||
|
||||
log() { printf '%s[%s]%s %s\n' "$C_BLUE" "$(date +%H:%M:%S)" "$C_RESET" "$*"; }
|
||||
ok() { printf '%s✓%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
|
||||
warn() { printf '%s⚠%s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; }
|
||||
err() { printf '%s✗%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; }
|
||||
skip() { printf '%s↪ skip%s %s\n' "$C_DIM" "$C_RESET" "$*"; }
|
||||
|
||||
require_debian() {
|
||||
if ! grep -q '^ID=debian' /etc/os-release 2>/dev/null; then
|
||||
err "This script targets Debian (read from /etc/os-release)."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_not_root() {
|
||||
if [[ $EUID -eq 0 ]]; then
|
||||
err "Run as your regular user (sudo is invoked where needed)."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local prompt="${1:-Proceed?}"
|
||||
read -r -p "$prompt [y/N] " ans
|
||||
[[ "$ans" =~ ^[yY]$ ]]
|
||||
}
|
||||
|
||||
# Install apt packages, skipping those already present. Idempotent.
|
||||
apt_install() {
|
||||
local missing=()
|
||||
for pkg in "$@"; do
|
||||
if ! dpkg -s "$pkg" >/dev/null 2>&1; then
|
||||
missing+=("$pkg")
|
||||
fi
|
||||
done
|
||||
if (( ${#missing[@]} == 0 )); then
|
||||
skip "All packages already present: $*"
|
||||
return 0
|
||||
fi
|
||||
log "apt install: ${missing[*]}"
|
||||
sudo apt-get install -y "${missing[@]}"
|
||||
ok "Installed: ${missing[*]}"
|
||||
}
|
||||
|
||||
# Append a line to a file iff not already present (exact match). Idempotent.
|
||||
ensure_line() {
|
||||
local line="$1"
|
||||
local file="$2"
|
||||
if grep -qxF -- "$line" "$file" 2>/dev/null; then
|
||||
skip "Already in $(basename "$file"): $line"
|
||||
else
|
||||
echo "$line" >> "$file"
|
||||
ok "Appended to $file: $line"
|
||||
fi
|
||||
}
|
||||
|
||||
# Same but with sudo (system files).
|
||||
ensure_line_sudo() {
|
||||
local line="$1"
|
||||
local file="$2"
|
||||
if sudo grep -qxF -- "$line" "$file" 2>/dev/null; then
|
||||
skip "Already in $(basename "$file"): $line"
|
||||
else
|
||||
echo "$line" | sudo tee -a "$file" >/dev/null
|
||||
ok "Appended to $file: $line"
|
||||
fi
|
||||
}
|
||||
Reference in New Issue
Block a user