feca-mailshots-plugin/scripts/deploy_remote.sh

222 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
ENV_FILE="${REPO_ROOT}/credentials/.env"
PLUGIN_SLUG="${PLUGIN_SLUG:-feca_mailshots_plugin}"
SOURCE_DIR="${SOURCE_DIR:-${REPO_ROOT}/${PLUGIN_SLUG}}"
DRY_RUN=0
usage() {
cat <<'USAGE'
Usage: scripts/deploy_remote.sh [--dry-run] [--source /path/to/plugin]
Deploys plugin files to DEPLOYMENT_DIRECTORY on the remote host using
REMOTE_SSH_* values from credentials/.env.
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
DRY_RUN=1
shift
;;
--source)
SOURCE_DIR="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ ! -f "${ENV_FILE}" ]]; then
echo "Error: credentials file not found: ${ENV_FILE}" >&2
exit 1
fi
if [[ ! -d "${SOURCE_DIR}" ]]; then
echo "Error: source directory not found: ${SOURCE_DIR}" >&2
exit 1
fi
PLUGIN_BASENAME="$(basename "${SOURCE_DIR}")"
PLUGIN_MAIN_FILE="${SOURCE_DIR}/${PLUGIN_BASENAME}.php"
if [[ ! -f "${PLUGIN_MAIN_FILE}" ]]; then
echo "Error: plugin main file not found: ${PLUGIN_MAIN_FILE}" >&2
exit 1
fi
COMPOSER_JSON="${REPO_ROOT}/composer.json"
COMPOSER_LOCK="${REPO_ROOT}/composer.lock"
LOCAL_VENDOR_DIR="${REPO_ROOT}/vendor"
if [[ ! -f "${COMPOSER_JSON}" || ! -f "${COMPOSER_LOCK}" ]]; then
echo "Error: missing composer.json/composer.lock in ${REPO_ROOT}" >&2
exit 1
fi
load_env_value() {
local key="$1"
local line
line="$(grep -E "^${key}=" "${ENV_FILE}" | tail -n 1 || true)"
line="${line#*=}"
line="${line%\"}"
line="${line#\"}"
line="${line%\'}"
line="${line#\'}"
printf '%s' "${line}"
}
SSH_HOST="$(load_env_value REMOTE_SSH_HOST)"
SSH_PORT="$(load_env_value REMOTE_SSH_PORT)"
SSH_USER="$(load_env_value REMOTE_SSH_USER)"
SSH_KEY_RAW="$(load_env_value REMOTE_SSH_KEY)"
REMOTE_DIR_RAW="$(load_env_value DEPLOYMENT_DIRECTORY)"
if [[ -z "${SSH_HOST}" || -z "${SSH_USER}" || -z "${SSH_KEY_RAW}" ]]; then
echo "Error: missing REMOTE_SSH_* values in ${ENV_FILE}" >&2
exit 1
fi
if [[ -z "${REMOTE_DIR_RAW}" ]]; then
echo "Error: missing DEPLOYMENT_DIRECTORY in ${ENV_FILE}" >&2
exit 1
fi
if [[ -z "${SSH_PORT}" ]]; then
SSH_PORT=22
fi
if [[ "${SSH_KEY_RAW}" = /* ]]; then
SSH_KEY_PATH="${SSH_KEY_RAW}"
else
SSH_KEY_PATH="${REPO_ROOT}/${SSH_KEY_RAW}"
fi
if [[ ! -f "${SSH_KEY_PATH}" ]]; then
echo "Error: SSH key not found: ${SSH_KEY_PATH}" >&2
exit 1
fi
SSH_TARGET="${SSH_USER}@${SSH_HOST}"
if [[ "${REMOTE_DIR_RAW}" = /* ]]; then
REMOTE_DIR="${REMOTE_DIR_RAW}"
else
REMOTE_DIR="/home/${SSH_USER}/${REMOTE_DIR_RAW}"
fi
REMOTE_PLUGIN_VENDOR_DIR="${REMOTE_DIR}/vendor"
CURRENT_VERSION="$(awk '
/Version:/ {
line = $0
sub(/^.*Version:[[:space:]]*/, "", line)
if (match(line, /^[0-9]+\.[0-9]+\.[0-9]+/)) {
print substr(line, RSTART, RLENGTH)
exit
}
}
' "${PLUGIN_MAIN_FILE}")"
if [[ -z "${CURRENT_VERSION}" ]]; then
echo "Error: could not parse Version: x.y.z from ${PLUGIN_MAIN_FILE}" >&2
exit 1
fi
IFS='.' read -r VER_MAJOR VER_MINOR VER_PATCH <<< "${CURRENT_VERSION}"
NEW_PATCH=$((VER_PATCH + 1))
NEW_VERSION="${VER_MAJOR}.${VER_MINOR}.${NEW_PATCH}"
if [[ "${DRY_RUN}" -eq 1 ]]; then
echo "Version bump (dry-run): ${CURRENT_VERSION} -> ${NEW_VERSION}"
else
TMP_FILE="${PLUGIN_MAIN_FILE}.tmp.$$"
awk -v new_version="${NEW_VERSION}" '
BEGIN { done = 0 }
{
if (!done && $0 ~ /^[[:space:]]*\*[[:space:]]*Version:[[:space:]]*[0-9]+\.[0-9]+\.[0-9]+[[:space:]]*$/) {
sub(/[0-9]+\.[0-9]+\.[0-9]+/, new_version)
done = 1
}
print
}
END {
if (!done) {
exit 2
}
}
' "${PLUGIN_MAIN_FILE}" > "${TMP_FILE}"
mv "${TMP_FILE}" "${PLUGIN_MAIN_FILE}"
echo "Version bumped: ${CURRENT_VERSION} -> ${NEW_VERSION}"
fi
echo "Remote host: ${SSH_TARGET}:${SSH_PORT}"
echo "Source dir: ${SOURCE_DIR}"
echo "Deploy target: ${REMOTE_DIR}"
echo "Vendor target: ${REMOTE_PLUGIN_VENDOR_DIR}"
if [[ "${DRY_RUN}" -eq 1 ]]; then
if [[ ! -f "${LOCAL_VENDOR_DIR}/autoload.php" ]]; then
echo "Warning: ${LOCAL_VENDOR_DIR}/autoload.php not found. Run scripts/install_dependencies.sh before real deploy."
fi
else
"${REPO_ROOT}/scripts/install_dependencies.sh" --skip-node
if [[ ! -f "${LOCAL_VENDOR_DIR}/autoload.php" ]]; then
echo "Error: ${LOCAL_VENDOR_DIR}/autoload.php is missing. Install dependencies first (scripts/install_dependencies.sh)." >&2
exit 1
fi
fi
ssh -p "${SSH_PORT}" \
-i "${SSH_KEY_PATH}" \
-o BatchMode=yes \
-o StrictHostKeyChecking=accept-new \
"${SSH_TARGET}" \
"mkdir -p '${REMOTE_DIR}' '${REMOTE_PLUGIN_VENDOR_DIR}'"
RSYNC_SSH="ssh -p ${SSH_PORT} -i ${SSH_KEY_PATH} -o BatchMode=yes -o StrictHostKeyChecking=accept-new"
RSYNC_ARGS=(
-avz
--delete
--exclude '.git/'
--exclude '.codex/'
--exclude '.DS_Store'
)
if [[ "${DRY_RUN}" -eq 1 ]]; then
RSYNC_ARGS+=(-n)
fi
rsync "${RSYNC_ARGS[@]}" \
-e "${RSYNC_SSH}" \
"${SOURCE_DIR}/" \
"${SSH_TARGET}:${REMOTE_DIR}/"
VENDOR_RSYNC_ARGS=(
-avz
--delete
)
if [[ "${DRY_RUN}" -eq 1 ]]; then
VENDOR_RSYNC_ARGS+=(-n)
fi
rsync "${VENDOR_RSYNC_ARGS[@]}" \
-e "${RSYNC_SSH}" \
"${LOCAL_VENDOR_DIR}/" \
"${SSH_TARGET}:${REMOTE_PLUGIN_VENDOR_DIR}/"
if [[ "${DRY_RUN}" -eq 1 ]]; then
echo "Dry-run complete. No remote files were changed."
else
echo "Deploy complete."
fi