feat: production release with React SPA, file attachments, and deploy tooling
Backend: - Add file_handlers.go: presigned upload/download for item attachments - Add item_files.go: item file and thumbnail DB operations - Add migration 011: item_files table and thumbnail_key column - Update items/projects/relationships DB with extended field support - Update routes: React SPA serving from web/dist, file upload endpoints - Update auth handlers and middleware for cookie + bearer token auth - Remove Go HTML templates (replaced by React SPA) - Update storage client for presigned URL generation Frontend: - Add TagInput component for tag/keyword entry - Add SVG assets for Silo branding and UI icons - Update API client and types for file uploads, auth, extended fields - Update AuthContext for session-based auth flow - Update LoginPage, ProjectsPage, SchemasPage, SettingsPage - Fix tsconfig.node.json Deployment: - Update config.prod.yaml: single-binary SPA layout at /opt/silo - Update silod.service: ReadOnlyPaths for /opt/silo - Add scripts/deploy.sh: build, package, ship, migrate, start - Update docker-compose.yaml and Dockerfile - Add frontend-spec.md design document
This commit is contained in:
@@ -1,458 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
#!/bin/bash
|
||||
# Deploy Silo to silo.kindred.internal
|
||||
#
|
||||
# Silo Deployment Script
|
||||
# Pulls from git and deploys silod on the local machine
|
||||
# Usage: ./scripts/deploy.sh [host]
|
||||
# host defaults to silo.kindred.internal
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./scripts/deploy.sh [options]
|
||||
#
|
||||
# Options:
|
||||
# --no-pull Skip git pull (use current checkout)
|
||||
# --no-build Skip build (use existing binary)
|
||||
# --restart-only Only restart the service
|
||||
# --status Show service status and exit
|
||||
# --help Show this help message
|
||||
#
|
||||
# This script should be run on silo.kindred.internal as root or with sudo.
|
||||
# Prerequisites:
|
||||
# - SSH access to the target host
|
||||
# - /etc/silo/silod.env must exist on target with credentials filled in
|
||||
# - PostgreSQL reachable from target at psql.kindred.internal
|
||||
# - MinIO reachable from target at minio.kindred.internal
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
REPO_URL="${SILO_REPO_URL:-https://gitea.kindred.internal/kindred/silo-0062.git}"
|
||||
REPO_BRANCH="${SILO_BRANCH:-main}"
|
||||
INSTALL_DIR="/opt/silo"
|
||||
TARGET="${1:-silo.kindred.internal}"
|
||||
DEPLOY_DIR="/opt/silo"
|
||||
CONFIG_DIR="/etc/silo"
|
||||
BINARY_NAME="silod"
|
||||
SERVICE_NAME="silod"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="${SCRIPT_DIR}/.."
|
||||
|
||||
# Flags
|
||||
DO_PULL=true
|
||||
DO_BUILD=true
|
||||
RESTART_ONLY=false
|
||||
STATUS_ONLY=false
|
||||
echo "=== Silo Deploy to ${TARGET} ==="
|
||||
|
||||
# Functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $*"
|
||||
}
|
||||
# --- Build locally ---
|
||||
echo "[1/6] Building Go binary..."
|
||||
cd "$PROJECT_DIR"
|
||||
GOOS=linux GOARCH=amd64 go build -o silod ./cmd/silod
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[OK]${NC} $*"
|
||||
}
|
||||
echo "[2/6] Building React frontend..."
|
||||
cd "$PROJECT_DIR/web"
|
||||
npm run build
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $*"
|
||||
}
|
||||
# --- Package ---
|
||||
echo "[3/6] Packaging..."
|
||||
STAGING=$(mktemp -d)
|
||||
trap "rm -rf $STAGING" EXIT
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*" >&2
|
||||
}
|
||||
mkdir -p "$STAGING/bin"
|
||||
mkdir -p "$STAGING/web"
|
||||
mkdir -p "$STAGING/schemas"
|
||||
mkdir -p "$STAGING/migrations"
|
||||
|
||||
die() {
|
||||
log_error "$*"
|
||||
cp "$PROJECT_DIR/silod" "$STAGING/bin/silod"
|
||||
cp -r "$PROJECT_DIR/web/dist" "$STAGING/web/dist"
|
||||
cp "$PROJECT_DIR/schemas/"*.yaml "$STAGING/schemas/"
|
||||
cp "$PROJECT_DIR/migrations/"*.sql "$STAGING/migrations/"
|
||||
cp "$PROJECT_DIR/deployments/config.prod.yaml" "$STAGING/config.yaml"
|
||||
cp "$PROJECT_DIR/deployments/systemd/silod.service" "$STAGING/silod.service"
|
||||
cp "$PROJECT_DIR/deployments/systemd/silod.env.example" "$STAGING/silod.env.example"
|
||||
|
||||
TARBALL=$(mktemp --suffix=.tar.gz)
|
||||
tar -czf "$TARBALL" -C "$STAGING" .
|
||||
echo " Package: $(du -h "$TARBALL" | cut -f1)"
|
||||
|
||||
# --- Deploy ---
|
||||
echo "[4/6] Uploading to ${TARGET}..."
|
||||
scp "$TARBALL" "${TARGET}:/tmp/silo-deploy.tar.gz"
|
||||
|
||||
echo "[5/6] Installing on ${TARGET}..."
|
||||
ssh "$TARGET" bash -s <<'REMOTE'
|
||||
set -euo pipefail
|
||||
|
||||
DEPLOY_DIR="/opt/silo"
|
||||
CONFIG_DIR="/etc/silo"
|
||||
|
||||
# Create directories
|
||||
sudo mkdir -p "$DEPLOY_DIR/bin" "$DEPLOY_DIR/web" "$DEPLOY_DIR/schemas" "$DEPLOY_DIR/migrations"
|
||||
sudo mkdir -p "$CONFIG_DIR"
|
||||
|
||||
# Stop service if running
|
||||
if systemctl is-active --quiet silod 2>/dev/null; then
|
||||
echo " Stopping silod..."
|
||||
sudo systemctl stop silod
|
||||
fi
|
||||
|
||||
# Extract
|
||||
echo " Extracting..."
|
||||
sudo tar -xzf /tmp/silo-deploy.tar.gz -C "$DEPLOY_DIR"
|
||||
sudo chmod +x "$DEPLOY_DIR/bin/silod"
|
||||
rm -f /tmp/silo-deploy.tar.gz
|
||||
|
||||
# Install config if not present (don't overwrite existing)
|
||||
if [ ! -f "$CONFIG_DIR/config.yaml" ]; then
|
||||
echo " Installing default config..."
|
||||
sudo cp "$DEPLOY_DIR/config.yaml" "$CONFIG_DIR/config.yaml" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Install env template if not present
|
||||
if [ ! -f "$CONFIG_DIR/silod.env" ]; then
|
||||
echo " WARNING: /etc/silo/silod.env does not exist!"
|
||||
echo " Copying template..."
|
||||
sudo cp "$DEPLOY_DIR/silod.env.example" "$CONFIG_DIR/silod.env"
|
||||
echo " Edit /etc/silo/silod.env with your credentials before starting the service."
|
||||
fi
|
||||
|
||||
# Install systemd service
|
||||
echo " Installing systemd service..."
|
||||
sudo cp "$DEPLOY_DIR/silod.service" /etc/systemd/system/silod.service
|
||||
|
||||
# Set ownership
|
||||
sudo chown -R silo:silo "$DEPLOY_DIR" 2>/dev/null || true
|
||||
sudo chmod 600 "$CONFIG_DIR/silod.env" 2>/dev/null || true
|
||||
|
||||
echo " Files installed to $DEPLOY_DIR"
|
||||
REMOTE
|
||||
|
||||
echo "[6/6] Running migrations and starting service..."
|
||||
ssh "$TARGET" bash -s <<'REMOTE'
|
||||
set -euo pipefail
|
||||
|
||||
DEPLOY_DIR="/opt/silo"
|
||||
CONFIG_DIR="/etc/silo"
|
||||
|
||||
# Source env for migration
|
||||
if [ -f "$CONFIG_DIR/silod.env" ]; then
|
||||
set -a
|
||||
source "$CONFIG_DIR/silod.env"
|
||||
set +a
|
||||
fi
|
||||
|
||||
# Run migrations
|
||||
if command -v psql &>/dev/null && [ -n "${SILO_DB_PASSWORD:-}" ]; then
|
||||
echo " Running migrations..."
|
||||
for f in "$DEPLOY_DIR/migrations/"*.sql; do
|
||||
echo " $(basename "$f")"
|
||||
PGPASSWORD="$SILO_DB_PASSWORD" psql \
|
||||
-h psql.kindred.internal -p 5432 \
|
||||
-U silo -d silo \
|
||||
-f "$f" -q 2>&1 | grep -v "already exists" || true
|
||||
done
|
||||
echo " Migrations complete."
|
||||
else
|
||||
echo " WARNING: psql not available or SILO_DB_PASSWORD not set, skipping migrations."
|
||||
echo " Run migrations manually: PGPASSWORD=... psql -h psql.kindred.internal -U silo -d silo -f /opt/silo/migrations/NNN_name.sql"
|
||||
fi
|
||||
|
||||
# Start service
|
||||
echo " Starting silod..."
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable silod
|
||||
sudo systemctl start silod
|
||||
sleep 2
|
||||
if systemctl is-active --quiet silod; then
|
||||
echo " silod is running!"
|
||||
else
|
||||
echo " ERROR: silod failed to start. Check: journalctl -u silod -n 50"
|
||||
exit 1
|
||||
}
|
||||
|
||||
show_help() {
|
||||
head -18 "$0" | grep -E '^#' | sed 's/^# *//'
|
||||
exit 0
|
||||
}
|
||||
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
die "This script must be run as root (use sudo)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_dependencies() {
|
||||
log_info "Checking dependencies..."
|
||||
|
||||
# Add common Go install locations to PATH
|
||||
if [[ -d /usr/local/go/bin ]]; then
|
||||
export PATH=$PATH:/usr/local/go/bin
|
||||
fi
|
||||
if [[ -d /opt/go/bin ]]; then
|
||||
export PATH=$PATH:/opt/go/bin
|
||||
fi
|
||||
|
||||
local missing=()
|
||||
|
||||
command -v git >/dev/null 2>&1 || missing+=("git")
|
||||
command -v go >/dev/null 2>&1 || missing+=("go (golang)")
|
||||
command -v systemctl >/dev/null 2>&1 || missing+=("systemctl")
|
||||
|
||||
if [[ ${#missing[@]} -gt 0 ]]; then
|
||||
die "Missing required commands: ${missing[*]}"
|
||||
fi
|
||||
|
||||
# Check Go version
|
||||
local go_version
|
||||
go_version=$(go version | grep -oP 'go\d+\.\d+' | head -1)
|
||||
log_info "Found Go version: ${go_version}"
|
||||
|
||||
log_success "All dependencies available"
|
||||
}
|
||||
|
||||
setup_directories() {
|
||||
log_info "Setting up directories..."
|
||||
|
||||
# Create directories if they don't exist
|
||||
mkdir -p "${INSTALL_DIR}/bin"
|
||||
mkdir -p "${INSTALL_DIR}/src"
|
||||
mkdir -p "${CONFIG_DIR}/schemas"
|
||||
mkdir -p /var/log/silo
|
||||
|
||||
# Create silo user if it doesn't exist
|
||||
if ! id -u silo >/dev/null 2>&1; then
|
||||
useradd -r -m -d "${INSTALL_DIR}" -s /sbin/nologin -c "Silo Service" silo
|
||||
log_info "Created silo user"
|
||||
fi
|
||||
|
||||
log_success "Directories ready"
|
||||
}
|
||||
|
||||
git_pull() {
|
||||
log_info "Pulling latest code from ${REPO_BRANCH}..."
|
||||
|
||||
local src_dir="${INSTALL_DIR}/src"
|
||||
|
||||
if [[ -d "${src_dir}/.git" ]]; then
|
||||
# Existing checkout - pull updates
|
||||
cd "${src_dir}"
|
||||
git fetch origin
|
||||
git checkout "${REPO_BRANCH}"
|
||||
git reset --hard "origin/${REPO_BRANCH}"
|
||||
log_success "Updated to $(git rev-parse --short HEAD)"
|
||||
else
|
||||
# Fresh clone
|
||||
log_info "Cloning repository..."
|
||||
rm -rf "${src_dir}"
|
||||
git clone --branch "${REPO_BRANCH}" "${REPO_URL}" "${src_dir}"
|
||||
cd "${src_dir}"
|
||||
log_success "Cloned $(git rev-parse --short HEAD)"
|
||||
fi
|
||||
|
||||
# Show version info
|
||||
local version
|
||||
version=$(git describe --tags --always --dirty 2>/dev/null || git rev-parse --short HEAD)
|
||||
log_info "Version: ${version}"
|
||||
}
|
||||
|
||||
build_binary() {
|
||||
log_info "Building ${BINARY_NAME}..."
|
||||
|
||||
local src_dir="${INSTALL_DIR}/src"
|
||||
cd "${src_dir}"
|
||||
|
||||
# Get version from git
|
||||
local version
|
||||
version=$(git describe --tags --always --dirty 2>/dev/null || git rev-parse --short HEAD)
|
||||
|
||||
local ldflags="-w -s -X main.Version=${version}"
|
||||
|
||||
# Build
|
||||
CGO_ENABLED=0 go build -ldflags="${ldflags}" -o "${INSTALL_DIR}/bin/${BINARY_NAME}" ./cmd/silod
|
||||
|
||||
if [[ ! -f "${INSTALL_DIR}/bin/${BINARY_NAME}" ]]; then
|
||||
die "Build failed: binary not found"
|
||||
fi
|
||||
|
||||
chmod 755 "${INSTALL_DIR}/bin/${BINARY_NAME}"
|
||||
|
||||
local size
|
||||
size=$(du -h "${INSTALL_DIR}/bin/${BINARY_NAME}" | cut -f1)
|
||||
log_success "Built ${BINARY_NAME} (${size})"
|
||||
}
|
||||
|
||||
install_config() {
|
||||
log_info "Installing configuration..."
|
||||
|
||||
local src_dir="${INSTALL_DIR}/src"
|
||||
|
||||
# Install config file if it doesn't exist or is different
|
||||
if [[ ! -f "${CONFIG_DIR}/config.yaml" ]]; then
|
||||
cp "${src_dir}/deployments/config.prod.yaml" "${CONFIG_DIR}/config.yaml"
|
||||
chmod 644 "${CONFIG_DIR}/config.yaml"
|
||||
chown root:silo "${CONFIG_DIR}/config.yaml"
|
||||
log_info "Installed config.yaml"
|
||||
else
|
||||
log_info "Config file exists, not overwriting"
|
||||
fi
|
||||
|
||||
# Install schemas (always update)
|
||||
rm -rf "${CONFIG_DIR}/schemas/"*
|
||||
cp -r "${src_dir}/schemas/"* "${CONFIG_DIR}/schemas/"
|
||||
chmod -R 644 "${CONFIG_DIR}/schemas/"*
|
||||
chown -R root:silo "${CONFIG_DIR}/schemas"
|
||||
log_success "Schemas installed"
|
||||
|
||||
# Check environment file
|
||||
if [[ ! -f "${CONFIG_DIR}/silod.env" ]]; then
|
||||
cp "${src_dir}/deployments/systemd/silod.env.example" "${CONFIG_DIR}/silod.env"
|
||||
chmod 600 "${CONFIG_DIR}/silod.env"
|
||||
chown root:silo "${CONFIG_DIR}/silod.env"
|
||||
log_warn "Created ${CONFIG_DIR}/silod.env - EDIT THIS FILE WITH CREDENTIALS!"
|
||||
fi
|
||||
}
|
||||
|
||||
install_systemd() {
|
||||
log_info "Installing systemd service..."
|
||||
|
||||
local src_dir="${INSTALL_DIR}/src"
|
||||
local service_file="${src_dir}/deployments/systemd/silod.service"
|
||||
|
||||
if [[ -f "${service_file}" ]]; then
|
||||
cp "${service_file}" /etc/systemd/system/silod.service
|
||||
chmod 644 /etc/systemd/system/silod.service
|
||||
systemctl daemon-reload
|
||||
log_success "Systemd service installed"
|
||||
else
|
||||
die "Service file not found: ${service_file}"
|
||||
fi
|
||||
}
|
||||
|
||||
set_permissions() {
|
||||
log_info "Setting permissions..."
|
||||
|
||||
chown -R silo:silo "${INSTALL_DIR}"
|
||||
chown root:silo "${CONFIG_DIR}"
|
||||
chmod 750 "${CONFIG_DIR}"
|
||||
chown silo:silo /var/log/silo
|
||||
chmod 750 /var/log/silo
|
||||
|
||||
# Binary should be owned by root but executable by silo
|
||||
chown root:root "${INSTALL_DIR}/bin/${BINARY_NAME}"
|
||||
chmod 755 "${INSTALL_DIR}/bin/${BINARY_NAME}"
|
||||
|
||||
log_success "Permissions set"
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
log_info "Restarting ${SERVICE_NAME} service..."
|
||||
|
||||
# Enable if not already
|
||||
systemctl enable "${SERVICE_NAME}" >/dev/null 2>&1 || true
|
||||
|
||||
# Restart
|
||||
systemctl restart "${SERVICE_NAME}"
|
||||
|
||||
# Wait for startup
|
||||
sleep 2
|
||||
|
||||
if systemctl is-active --quiet "${SERVICE_NAME}"; then
|
||||
log_success "Service started successfully"
|
||||
else
|
||||
log_error "Service failed to start"
|
||||
journalctl -u "${SERVICE_NAME}" -n 20 --no-pager || true
|
||||
die "Deployment failed: service not running"
|
||||
fi
|
||||
}
|
||||
|
||||
run_migrations() {
|
||||
log_info "Running database migrations..."
|
||||
|
||||
local src_dir="${INSTALL_DIR}/src"
|
||||
local migrations_dir="${src_dir}/migrations"
|
||||
local env_file="${CONFIG_DIR}/silod.env"
|
||||
|
||||
if [[ ! -d "${migrations_dir}" ]]; then
|
||||
die "Migrations directory not found: ${migrations_dir}"
|
||||
fi
|
||||
|
||||
# Source env file for DB password
|
||||
if [[ -f "${env_file}" ]]; then
|
||||
# shellcheck disable=SC1090
|
||||
source "${env_file}"
|
||||
fi
|
||||
|
||||
# Read DB config from production config
|
||||
local db_host db_port db_name db_user db_password
|
||||
db_host=$(grep -A10 '^database:' "${CONFIG_DIR}/config.yaml" | grep 'host:' | head -1 | awk '{print $2}' | tr -d '"')
|
||||
db_port=$(grep -A10 '^database:' "${CONFIG_DIR}/config.yaml" | grep 'port:' | head -1 | awk '{print $2}')
|
||||
db_name=$(grep -A10 '^database:' "${CONFIG_DIR}/config.yaml" | grep 'name:' | head -1 | awk '{print $2}' | tr -d '"')
|
||||
db_user=$(grep -A10 '^database:' "${CONFIG_DIR}/config.yaml" | grep 'user:' | head -1 | awk '{print $2}' | tr -d '"')
|
||||
db_password="${SILO_DB_PASSWORD:-}"
|
||||
|
||||
db_host="${db_host:-localhost}"
|
||||
db_port="${db_port:-5432}"
|
||||
db_name="${db_name:-silo}"
|
||||
db_user="${db_user:-silo}"
|
||||
|
||||
if [[ -z "${db_password}" ]]; then
|
||||
log_warn "SILO_DB_PASSWORD not set — skipping migrations"
|
||||
log_warn "Run migrations manually: psql -h ${db_host} -U ${db_user} -d ${db_name} -f migrations/009_auth.sql"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check psql is available
|
||||
if ! command -v psql >/dev/null 2>&1; then
|
||||
log_warn "psql not found — skipping automatic migrations"
|
||||
log_warn "Run migrations manually: psql -h ${db_host} -U ${db_user} -d ${db_name} -f migrations/009_auth.sql"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Wait for database to be reachable
|
||||
local retries=0
|
||||
while ! PGPASSWORD="${db_password}" psql -h "${db_host}" -p "${db_port}" -U "${db_user}" -d "${db_name}" -c '\q' 2>/dev/null; do
|
||||
retries=$((retries + 1))
|
||||
if [[ ${retries} -ge 5 ]]; then
|
||||
log_warn "Could not connect to database after 5 attempts — skipping migrations"
|
||||
return 0
|
||||
fi
|
||||
log_info "Waiting for database... (attempt ${retries}/5)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Apply each migration, skipping ones that have already been applied
|
||||
local applied=0
|
||||
local skipped=0
|
||||
for migration in "${migrations_dir}"/*.sql; do
|
||||
if [[ ! -f "${migration}" ]]; then
|
||||
continue
|
||||
fi
|
||||
local name
|
||||
name=$(basename "${migration}")
|
||||
if PGPASSWORD="${db_password}" psql -h "${db_host}" -p "${db_port}" \
|
||||
-U "${db_user}" -d "${db_name}" -f "${migration}" 2>/dev/null; then
|
||||
log_info "Applied: ${name}"
|
||||
applied=$((applied + 1))
|
||||
else
|
||||
skipped=$((skipped + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
log_success "Migrations complete (${applied} applied, ${skipped} already present)"
|
||||
}
|
||||
|
||||
verify_deployment() {
|
||||
log_info "Verifying deployment..."
|
||||
|
||||
# Wait a moment for service to fully start
|
||||
sleep 2
|
||||
|
||||
# Check health endpoint
|
||||
local health_status
|
||||
health_status=$(curl -sf http://localhost:8080/health 2>/dev/null || echo "FAILED")
|
||||
|
||||
if [[ "${health_status}" == *"ok"* ]] || [[ "${health_status}" == *"healthy"* ]] || [[ "${health_status}" == "{}" ]]; then
|
||||
log_success "Health check passed"
|
||||
else
|
||||
log_warn "Health check returned: ${health_status}"
|
||||
fi
|
||||
|
||||
# Check ready endpoint (includes DB and MinIO)
|
||||
local ready_status
|
||||
ready_status=$(curl -sf http://localhost:8080/ready 2>/dev/null || echo "FAILED")
|
||||
|
||||
if [[ "${ready_status}" == *"ok"* ]] || [[ "${ready_status}" == *"ready"* ]] || [[ "${ready_status}" == "{}" ]]; then
|
||||
log_success "Readiness check passed (DB and MinIO connected)"
|
||||
else
|
||||
log_warn "Readiness check returned: ${ready_status}"
|
||||
log_warn "Check credentials in ${CONFIG_DIR}/silod.env"
|
||||
fi
|
||||
|
||||
# Show version
|
||||
log_info "Deployed version: $("${INSTALL_DIR}/bin/${BINARY_NAME}" --version 2>/dev/null || echo 'unknown')"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo ""
|
||||
log_info "Service Status"
|
||||
echo "============================================"
|
||||
systemctl status "${SERVICE_NAME}" --no-pager -l || true
|
||||
echo ""
|
||||
echo "Recent logs:"
|
||||
journalctl -u "${SERVICE_NAME}" -n 10 --no-pager || true
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--no-pull)
|
||||
DO_PULL=false
|
||||
shift
|
||||
;;
|
||||
--no-build)
|
||||
DO_BUILD=false
|
||||
shift
|
||||
;;
|
||||
--restart-only)
|
||||
RESTART_ONLY=true
|
||||
shift
|
||||
;;
|
||||
--status)
|
||||
STATUS_ONLY=true
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
die "Unknown option: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo ""
|
||||
log_info "Silo Deployment Script"
|
||||
log_info "======================"
|
||||
echo ""
|
||||
|
||||
check_root
|
||||
|
||||
if [[ "${STATUS_ONLY}" == "true" ]]; then
|
||||
show_status
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${RESTART_ONLY}" == "true" ]]; then
|
||||
restart_service
|
||||
verify_deployment
|
||||
exit 0
|
||||
fi
|
||||
|
||||
check_dependencies
|
||||
setup_directories
|
||||
|
||||
if [[ "${DO_PULL}" == "true" ]]; then
|
||||
git_pull
|
||||
else
|
||||
log_info "Skipping git pull (--no-pull)"
|
||||
cd "${INSTALL_DIR}/src"
|
||||
fi
|
||||
|
||||
if [[ "${DO_BUILD}" == "true" ]]; then
|
||||
build_binary
|
||||
else
|
||||
log_info "Skipping build (--no-build)"
|
||||
fi
|
||||
|
||||
install_config
|
||||
run_migrations
|
||||
install_systemd
|
||||
set_permissions
|
||||
restart_service
|
||||
verify_deployment
|
||||
|
||||
echo ""
|
||||
log_success "============================================"
|
||||
log_success "Deployment complete!"
|
||||
log_success "============================================"
|
||||
echo ""
|
||||
echo "Useful commands:"
|
||||
echo " sudo systemctl status silod # Check service status"
|
||||
echo " sudo journalctl -u silod -f # Follow logs"
|
||||
echo " curl http://localhost:8080/health # Health check"
|
||||
echo ""
|
||||
}
|
||||
|
||||
main "$@"
|
||||
fi
|
||||
REMOTE
|
||||
|
||||
echo ""
|
||||
echo "=== Deploy complete ==="
|
||||
echo " Backend: https://${TARGET} (port 8080)"
|
||||
echo " React SPA served from /opt/silo/web/dist/"
|
||||
echo " Logs: ssh ${TARGET} journalctl -u silod -f"
|
||||
|
||||
Reference in New Issue
Block a user