232 lines
5.8 KiB
Bash
Executable File
232 lines
5.8 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_PARENT_DIR="$(dirname "${REMOTE_DIR}")"
|
|
REMOTE_VENDOR_DIR="${REMOTE_PARENT_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_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 'composer install --no-dev' before real deploy."
|
|
fi
|
|
else
|
|
if command -v composer >/dev/null 2>&1; then
|
|
echo "Installing/updating PHP dependencies from composer.lock..."
|
|
(
|
|
cd "${REPO_ROOT}"
|
|
composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
|
|
)
|
|
else
|
|
echo "composer not found on PATH; using existing ${LOCAL_VENDOR_DIR}."
|
|
fi
|
|
if [[ ! -f "${LOCAL_VENDOR_DIR}/autoload.php" ]]; then
|
|
echo "Error: ${LOCAL_VENDOR_DIR}/autoload.php is missing. Install dependencies first (composer install --no-dev)." >&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_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}/"
|
|
|
|
# Keep root-level Composer dependencies in sync for plugin autoloading.
|
|
# Intentionally avoids --delete so we don't remove unrelated packages that may share this vendor dir.
|
|
VENDOR_RSYNC_ARGS=(
|
|
-avz
|
|
)
|
|
if [[ "${DRY_RUN}" -eq 1 ]]; then
|
|
VENDOR_RSYNC_ARGS+=(-n)
|
|
fi
|
|
|
|
rsync "${VENDOR_RSYNC_ARGS[@]}" \
|
|
-e "${RSYNC_SSH}" \
|
|
"${LOCAL_VENDOR_DIR}/" \
|
|
"${SSH_TARGET}:${REMOTE_VENDOR_DIR}/"
|
|
|
|
if [[ "${DRY_RUN}" -eq 1 ]]; then
|
|
echo "Dry-run complete. No remote files were changed."
|
|
else
|
|
echo "Deploy complete."
|
|
fi
|