227 lines
4.8 KiB
Bash
Executable File
227 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SERVICE_NAME="${1:-}"
|
|
|
|
if [ -z "$SERVICE_NAME" ]; then
|
|
echo "Usage: ./deploy-core-service.sh <service-name>"
|
|
exit 1
|
|
fi
|
|
|
|
CONFIG_FILE="/opt/appfactory/config/appfactory.env"
|
|
|
|
set -a
|
|
source "$CONFIG_FILE"
|
|
set +a
|
|
|
|
export DOCKER_CONFIG="/tmp/.docker"
|
|
mkdir -p "$DOCKER_CONFIG"
|
|
|
|
DB_FILE="/opt/appfactory/data/appfactory/appfactory.db"
|
|
SERVICE_DIR="$WORKSPACE_DIR/$SERVICE_NAME"
|
|
DEPLOY_DIR="$APPFACTORY_DIR/deploy"
|
|
|
|
TRIGGER_SOURCE="${APPFACTORY_TRIGGER_SOURCE:-cli}"
|
|
TRIGGERED_BY_USER_ID="${APPFACTORY_TRIGGERED_BY_USER_ID:-}"
|
|
TRIGGERED_BY_USERNAME="${APPFACTORY_TRIGGERED_BY_USERNAME:-}"
|
|
TRIGGERED_BY_DISPLAY_NAME="${APPFACTORY_TRIGGERED_BY_DISPLAY_NAME:-}"
|
|
COMMIT_AUTHOR="${APPFACTORY_COMMIT_AUTHOR:-}"
|
|
PUSHER="${APPFACTORY_PUSHER:-}"
|
|
|
|
if [ ! -d "$SERVICE_DIR" ]; then
|
|
echo "Missing service directory: $SERVICE_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -f "$SERVICE_DIR/Dockerfile" ]; then
|
|
echo "Missing Dockerfile: $SERVICE_DIR/Dockerfile"
|
|
exit 1
|
|
fi
|
|
|
|
DEPLOY_ID="$(python3 - "$DB_FILE" "$SERVICE_NAME" "$TRIGGER_SOURCE" "$TRIGGERED_BY_USER_ID" "$TRIGGERED_BY_USERNAME" "$TRIGGERED_BY_DISPLAY_NAME" "$COMMIT_AUTHOR" "$PUSHER" <<'PY'
|
|
import sqlite3
|
|
import sys
|
|
|
|
db_file = sys.argv[1]
|
|
app_id = sys.argv[2]
|
|
trigger_source = sys.argv[3]
|
|
triggered_by_user_id = sys.argv[4] or None
|
|
triggered_by_username = sys.argv[5] or None
|
|
triggered_by_display_name = sys.argv[6] or None
|
|
commit_author = sys.argv[7] or None
|
|
pusher = sys.argv[8] or None
|
|
|
|
con = sqlite3.connect(db_file)
|
|
|
|
cur = con.execute(
|
|
"""
|
|
INSERT INTO deployments (
|
|
app_id,
|
|
kind,
|
|
status,
|
|
started_at,
|
|
trigger_source,
|
|
triggered_by_user_id,
|
|
triggered_by_username,
|
|
triggered_by_display_name,
|
|
commit_author,
|
|
pusher
|
|
)
|
|
VALUES (?, ?, ?, CURRENT_TIMESTAMP, ?, ?, ?, ?, ?, ?)
|
|
""",
|
|
(
|
|
app_id,
|
|
"core",
|
|
"running",
|
|
trigger_source,
|
|
triggered_by_user_id,
|
|
triggered_by_username,
|
|
triggered_by_display_name,
|
|
commit_author,
|
|
pusher,
|
|
),
|
|
)
|
|
|
|
con.commit()
|
|
print(cur.lastrowid)
|
|
con.close()
|
|
PY
|
|
)"
|
|
|
|
TMP_DIR="$(mktemp -d)"
|
|
STDOUT_FILE="$TMP_DIR/stdout.log"
|
|
STDERR_FILE="$TMP_DIR/stderr.log"
|
|
|
|
touch "$STDOUT_FILE" "$STDERR_FILE"
|
|
|
|
finish_deploy() {
|
|
local status="$1"
|
|
local returncode="$2"
|
|
|
|
python3 - "$DB_FILE" "$DEPLOY_ID" "$status" "$returncode" "$STDOUT_FILE" "$STDERR_FILE" <<'PY'
|
|
import sqlite3
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
db_file = sys.argv[1]
|
|
deploy_id = sys.argv[2]
|
|
status = sys.argv[3]
|
|
returncode = int(sys.argv[4])
|
|
stdout_file = Path(sys.argv[5])
|
|
stderr_file = Path(sys.argv[6])
|
|
|
|
stdout = stdout_file.read_text(errors="replace") if stdout_file.exists() else ""
|
|
stderr = stderr_file.read_text(errors="replace") if stderr_file.exists() else ""
|
|
|
|
con = sqlite3.connect(db_file)
|
|
|
|
con.execute(
|
|
"""
|
|
UPDATE deployments
|
|
SET status = ?,
|
|
finished_at = CURRENT_TIMESTAMP,
|
|
stdout = ?,
|
|
stderr = ?,
|
|
returncode = ?
|
|
WHERE id = ?
|
|
""",
|
|
(status, stdout, stderr, returncode, deploy_id),
|
|
)
|
|
|
|
con.commit()
|
|
con.close()
|
|
PY
|
|
}
|
|
|
|
run_step() {
|
|
local title="$1"
|
|
shift
|
|
|
|
{
|
|
echo ""
|
|
echo "=================================================="
|
|
echo "$title"
|
|
echo "=================================================="
|
|
"$@"
|
|
} >>"$STDOUT_FILE" 2>>"$STDERR_FILE"
|
|
}
|
|
|
|
cleanup_conflicting_containers() {
|
|
local service="$1"
|
|
|
|
docker ps -a --format "{{.ID}} {{.Names}}" \
|
|
| awk -v svc="$service" '$2 == svc || $2 ~ ("_" svc "$") { print $1 }' \
|
|
| while read -r container_id; do
|
|
if [ -n "$container_id" ]; then
|
|
echo "Removing conflicting container: $container_id"
|
|
docker rm -f "$container_id" || true
|
|
fi
|
|
done
|
|
}
|
|
|
|
set +e
|
|
|
|
run_step "Updating source" bash -c "
|
|
cd '$SERVICE_DIR'
|
|
|
|
git \
|
|
-c safe.directory='$SERVICE_DIR' \
|
|
fetch origin main
|
|
|
|
git \
|
|
-c safe.directory='$SERVICE_DIR' \
|
|
reset --hard origin/main
|
|
"
|
|
|
|
RESULT=$?
|
|
|
|
if [ "$RESULT" -eq 0 ]; then
|
|
run_step "Building image" docker build --pull --no-cache -t "$SERVICE_NAME:latest" "$SERVICE_DIR"
|
|
RESULT=$?
|
|
fi
|
|
|
|
if [ "$RESULT" -eq 0 ]; then
|
|
run_step "Cleaning conflicting containers" cleanup_conflicting_containers "$SERVICE_NAME"
|
|
RESULT=$?
|
|
fi
|
|
|
|
if [ "$RESULT" -eq 0 ]; then
|
|
run_step "Recreating container" bash -c "
|
|
cd '$DEPLOY_DIR'
|
|
|
|
docker compose \
|
|
--env-file '$CONFIG_FILE' \
|
|
-f docker-compose.yml \
|
|
-f apps-compose.yml \
|
|
up -d --force-recreate '$SERVICE_NAME'
|
|
"
|
|
RESULT=$?
|
|
fi
|
|
|
|
set -e
|
|
|
|
if [ "$RESULT" -eq 0 ]; then
|
|
finish_deploy "success" 0
|
|
|
|
cat "$STDOUT_FILE"
|
|
cat "$STDERR_FILE" >&2
|
|
|
|
echo ""
|
|
echo "DONE"
|
|
echo "Core service deployed: $SERVICE_NAME"
|
|
else
|
|
finish_deploy "failed" "$RESULT"
|
|
|
|
cat "$STDOUT_FILE"
|
|
cat "$STDERR_FILE" >&2
|
|
|
|
echo ""
|
|
echo "FAILED"
|
|
echo "Deployment ID: $DEPLOY_ID"
|
|
|
|
rm -rf "$TMP_DIR"
|
|
exit "$RESULT"
|
|
fi
|
|
|
|
rm -rf "$TMP_DIR"
|