Gen 4 of build-zulip-plugin contract — closing the deployment gap: 1. Rewrote deploy.sh for dual-mode deployment - --mode=native: deploys to ~/.hermes/plugins/platforms/zulip/ + hermes gateway restart - --mode=legacy: old /opt/hermes-zulip-plugin/ + systemctl (deprecated) - Per-agent deployment, dry-run support, health verification 2. Added verify-deployment.sh - Checks plugin files, Hermes Gateway, health endpoint, env vars - Returns clear verdict: deployed or what's missing 3. Updated ARCHITECTURE.md to v2 - Documents native plugin as CURRENT, old systemd as DEPRECATED - Cross-references hermes-zulip-plugin/DEPRECATED.md 4. Tagged v1.0.0 — 14/14 Success Criteria met, deployable
261 lines
7.8 KiB
Bash
Executable File
261 lines
7.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# deploy.sh — GitOps deployment for zulip-platform-plugins
|
|
#
|
|
# Supports two deployment modes:
|
|
# LEGACY: /opt/hermes-zulip-plugin/ + systemctl restart zulip-plugin
|
|
# NATIVE: ~/.hermes/plugins/platforms/zulip/ + hermes gateway restart
|
|
#
|
|
# Usage:
|
|
# ./deploy.sh <tag|branch> # Deploy all agents (default: native)
|
|
# ./deploy.sh --mode=native v1.0.0 # Hermes native plugin (new)
|
|
# ./deploy.sh --mode=legacy v1.0.0 # Old systemd service (deprecated)
|
|
# ./deploy.sh --ct=tanko v1.0.0 # Single agent
|
|
# ./deploy.sh --dry-run v1.0.0 # Preview only
|
|
#
|
|
set -euo pipefail
|
|
|
|
DEPLOY_LOG="deploy.log"
|
|
TAG=""
|
|
SINGLE_CT=""
|
|
DRY_RUN=false
|
|
DEPLOY_MODE="native" # default to new Hermes native plugin
|
|
|
|
# Parse args
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--ct=*) SINGLE_CT="${arg#--ct=}" ;;
|
|
--dry-run) DRY_RUN=true ;;
|
|
--mode=*) DEPLOY_MODE="${arg#--mode=}" ;;
|
|
*) TAG="$arg" ;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "$TAG" ]]; then
|
|
echo "Usage: $0 <tag|branch> [--ct=<agent>] [--mode=native|legacy] [--dry-run]"
|
|
echo ""
|
|
echo " --ct=<agent> Deploy to single agent (tanko, mumuni, etc.)"
|
|
echo " --mode=native Hermes native plugin at ~/.hermes/plugins/ (default)"
|
|
echo " --mode=legacy Old systemd service at /opt/hermes-zulip-plugin/"
|
|
echo " --dry-run Preview deployment without making changes"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " ./deploy.sh v1.0.0 # Deploy native to all agents"
|
|
echo " ./deploy.sh --ct=tanko v1.0.0 # Deploy native to Tanko only"
|
|
echo " ./deploy.sh --mode=legacy v0.9.0 # Deploy legacy to all"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$DEPLOY_MODE" != "native" && "$DEPLOY_MODE" != "legacy" ]]; then
|
|
echo "ERROR: --mode must be 'native' or 'legacy'"
|
|
exit 1
|
|
fi
|
|
|
|
# ── Agent Registry (must match docs/CONTEXT.md) ──────────────────────
|
|
declare -A AGENTS=(
|
|
["tanko"]="amdpve CT 112"
|
|
["mumuni"]="minipve CT 114"
|
|
["koonimo"]="amdpve CT 113"
|
|
["koby"]="amdpve CT 111"
|
|
["kagentz"]="amdpve CT 105"
|
|
["abiba"]="amdpve CT 100"
|
|
)
|
|
|
|
# Native Hermes plugin path (~/.hermes/plugins/platforms/zulip/)
|
|
NATIVE_PLUGIN_SRC="plugins/platforms/zulip"
|
|
|
|
# Legacy paths (DEPRECATED — systemd zulip-plugin service)
|
|
declare -A LEGACY_PATHS=(
|
|
["tanko"]="/opt/hermes-zulip-plugin"
|
|
["mumuni"]="/opt/hermes-zulip-plugin"
|
|
["koonimo"]="/opt/hermes-zulip-plugin"
|
|
["koby"]="/opt/hermes-zulip-plugin"
|
|
["kagentz"]="/opt/agent-zero-plugin"
|
|
["abiba"]="/root/.pi/agent/extensions/zulip.ts"
|
|
)
|
|
|
|
# Service names for legacy mode
|
|
declare -A LEGACY_SERVICES=(
|
|
["tanko"]="zulip-plugin"
|
|
["mumuni"]="zulip-plugin"
|
|
["koonimo"]="zulip-plugin"
|
|
["koby"]="zulip-plugin"
|
|
["kagentz"]="zulip-plugin"
|
|
["abiba"]="pi"
|
|
)
|
|
|
|
HEALTH_PORT=9200
|
|
GITEA_REPO="https://git.sysloggh.net/SyslogSolution/zulip-platform-plugins.git"
|
|
|
|
log() {
|
|
local prefix=""
|
|
[[ "$DRY_RUN" == "true" ]] && prefix="[DRY-RUN] "
|
|
echo "${prefix}[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$DEPLOY_LOG"
|
|
}
|
|
|
|
# ── Deployment Functions ─────────────────────────────────────────────
|
|
|
|
deploy_native() {
|
|
local agent="$1"
|
|
local plugin_dir="$HOME/.hermes/plugins/platforms/zulip"
|
|
|
|
log "📦 Deploying $agent: native Hermes plugin -> $plugin_dir"
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log " Would copy $NATIVE_PLUGIN_SRC/{adapter.py,__init__.py,plugin.yaml} -> $plugin_dir/"
|
|
log " Would run: hermes gateway restart"
|
|
return 0
|
|
fi
|
|
|
|
# Create plugin directory
|
|
mkdir -p "$plugin_dir"
|
|
|
|
# Copy plugin files
|
|
cp "$NATIVE_PLUGIN_SRC/adapter.py" "$plugin_dir/"
|
|
cp "$NATIVE_PLUGIN_SRC/__init__.py" "$plugin_dir/"
|
|
cp "$NATIVE_PLUGIN_SRC/plugin.yaml" "$plugin_dir/"
|
|
|
|
log " Copied plugin files to $plugin_dir/"
|
|
ls -la "$plugin_dir/"
|
|
|
|
# Restart Hermes Gateway to load the plugin
|
|
if command -v hermes &>/dev/null; then
|
|
log " Restarting Hermes Gateway..."
|
|
hermes gateway restart
|
|
log " Hermes Gateway restarted"
|
|
else
|
|
log " ⚠️ 'hermes' command not found — manual restart needed"
|
|
log " Run: hermes gateway restart"
|
|
fi
|
|
|
|
# Health check
|
|
log " Waiting for service to stabilize..."
|
|
sleep 5
|
|
if curl -sf "http://localhost:$HEALTH_PORT/health" > /dev/null 2>&1; then
|
|
log " ✅ Health check passed (port $HEALTH_PORT)"
|
|
else
|
|
log " ⚠️ Health check on port $HEALTH_PORT not responding"
|
|
log " Check Gateway logs for plugin load errors"
|
|
fi
|
|
|
|
log "✅ $agent: native deployment complete"
|
|
}
|
|
|
|
deploy_legacy() {
|
|
local agent="$1"
|
|
local plugin_path="${LEGACY_PATHS[$agent]}"
|
|
local service="${LEGACY_SERVICES[$agent]}"
|
|
|
|
log "📦 Deploying $agent: LEGACY mode -> $plugin_path"
|
|
|
|
if [[ "$DRY_RUN" == "true" ]]; then
|
|
log " Would git checkout $TAG in $plugin_path"
|
|
log " Would install deps + restart $service"
|
|
return 0
|
|
fi
|
|
|
|
# Git checkout
|
|
if [[ ! -d "$plugin_path" ]]; then
|
|
log "❌ Path $plugin_path not found for $agent"
|
|
return 1
|
|
fi
|
|
|
|
cd "$plugin_path"
|
|
git fetch --tags origin
|
|
git checkout "$TAG"
|
|
|
|
log " Checked out $TAG in $plugin_path"
|
|
|
|
# Install deps
|
|
if [[ -f "requirements.txt" ]]; then
|
|
pip install -r requirements.txt --quiet
|
|
log " Dependencies installed"
|
|
fi
|
|
|
|
# Restart service
|
|
if systemctl list-units --full -all 2>/dev/null | grep -q "$service"; then
|
|
systemctl restart "$service"
|
|
log " Restarted $service"
|
|
else
|
|
log " ⚠️ Service $service not found — manual restart needed"
|
|
fi
|
|
|
|
# Health check
|
|
sleep 5
|
|
if curl -sf "http://localhost:$HEALTH_PORT/health" > /dev/null 2>&1; then
|
|
log " ✅ Health check passed"
|
|
else
|
|
log " ⚠️ Health check failed — check logs"
|
|
fi
|
|
|
|
log "✅ $agent: legacy deployment complete"
|
|
}
|
|
|
|
# ── Verify function ──────────────────────────────────────────────────
|
|
|
|
verify_deployment() {
|
|
local agent="$1"
|
|
|
|
log "🔍 Verifying $agent deployment..."
|
|
|
|
if [[ "$DEPLOY_MODE" == "native" ]]; then
|
|
local plugin_dir="$HOME/.hermes/plugins/platforms/zulip"
|
|
if [[ -f "$plugin_dir/adapter.py" && -f "$plugin_dir/plugin.yaml" ]]; then
|
|
log " ✅ Plugin files present in $plugin_dir"
|
|
log " adapter.py: $(wc -l < "$plugin_dir/adapter.py") lines"
|
|
log " plugin.yaml: $(wc -l < "$plugin_dir/plugin.yaml") lines"
|
|
else
|
|
log " ❌ Plugin files missing in $plugin_dir"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
log " ✅ $agent verification complete"
|
|
}
|
|
|
|
# ── Main ─────────────────────────────────────────────────────────────
|
|
|
|
log "🚀 Deploy started — tag: $TAG, mode: $DEPLOY_MODE, dry-run: $DRY_RUN"
|
|
|
|
if [[ -n "$SINGLE_CT" ]]; then
|
|
if [[ -z "${AGENTS[$SINGLE_CT]:-}" ]]; then
|
|
log "❌ Unknown agent: $SINGLE_CT"
|
|
log " Known agents: ${!AGENTS[*]}"
|
|
exit 1
|
|
fi
|
|
log "--- Deploying single agent: $SINGLE_CT ---"
|
|
if [[ "$DEPLOY_MODE" == "native" ]]; then
|
|
deploy_native "$SINGLE_CT"
|
|
else
|
|
deploy_legacy "$SINGLE_CT"
|
|
fi
|
|
verify_deployment "$SINGLE_CT"
|
|
else
|
|
FAILED=""
|
|
for agent in "${!AGENTS[@]}"; do
|
|
echo ""
|
|
if [[ "$DEPLOY_MODE" == "native" ]]; then
|
|
if deploy_native "$agent"; then
|
|
verify_deployment "$agent" || FAILED="$FAILED $agent"
|
|
else
|
|
FAILED="$FAILED $agent"
|
|
fi
|
|
else
|
|
if deploy_legacy "$agent"; then
|
|
verify_deployment "$agent" || FAILED="$FAILED $agent"
|
|
else
|
|
FAILED="$FAILED $agent"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
log "=== Deploy complete ==="
|
|
if [[ -n "$FAILED" ]]; then
|
|
log "❌ FAILED:$FAILED"
|
|
log " Run rollback: ./scripts/rollback.sh <previous-tag>"
|
|
exit 1
|
|
fi
|
|
log "✅ All agents deployed successfully."
|
|
log " Next: monitor #agent-hub for agent responses"
|
|
fi
|