220 lines
9.3 KiB
Bash
Executable file
220 lines
9.3 KiB
Bash
Executable file
#!/bin/bash
|
|
set -euo pipefail
|
|
# ~SCRIPT~ deploy.sh
|
|
# * Copies a build to the specified target and performs updates.
|
|
# * The build should already be prepared elsewhere.
|
|
# * Run from project root folder.
|
|
# * Will create database dumps (using drush)
|
|
# * By default, runs all related drush commands.
|
|
|
|
#######################################
|
|
# Using deploy.sh
|
|
#######################################
|
|
# ~REQUIRED~
|
|
# SSH_TARGET:
|
|
# Server to push code to/run drush commands on (host aliases work if configured in $HOME/.ssh/config)
|
|
# DEPLOY_ENV:
|
|
# A label for the environment, used to name backup files, and select settings file
|
|
# Defaults to ${CI_ENVIRONMENT_NAME}, if available, which is automatically set by gitlab-ci
|
|
# DEPLOY_ROOT:
|
|
# Directory name for composer file, containing vendor+config sub-folders
|
|
|
|
# ~OPTIONAL~
|
|
# DRUPAL_DIR:
|
|
# Defaults to web
|
|
# BACKUP_DIR:
|
|
# Defaults to ~/backups
|
|
# BUILD_ROOT:
|
|
# Defaults to ${PWD}
|
|
# DRUSH_DISABLE:
|
|
# Set to "1" to disable ALL drush commands.
|
|
# May be needed if an install failed or is not already present.
|
|
# REMOTE_DRUSH:
|
|
# Defaults to ${DEPLOY_ROOT}/vendor/bin/drush
|
|
# UPDATE_SCRIPT:
|
|
# The post-deploy update routine, specified from perspective of the project root.
|
|
# This should know how to find drush or can use $1 for it (see update.sh).
|
|
# Defaults to scripts/update.sh
|
|
# UPDATE_DISABLE:
|
|
# Set to "1" to disable only update commands (e.g. drush updb)
|
|
# Note: system will be left in maintenance mode!
|
|
# drush state:set system.maintenance_mode FALSE
|
|
# DEBUG:
|
|
# Set to "1" to call show-vars.sh
|
|
# WEB_EXCLUDES:
|
|
# --exclude .well-known --exclude sites/default/files --exclude sites/default/settings.*.php"
|
|
|
|
#######################################
|
|
# Load env vars, if supplied
|
|
#######################################
|
|
[ $# -eq 1 ] && source "env-${1}"
|
|
|
|
#######################################
|
|
# DEFAULTS
|
|
#######################################
|
|
_backup_dir="~/backups"
|
|
_config_dir="config" # Folder under deploy root with config
|
|
_remote_drush="${DEPLOY_ROOT:-}/vendor/bin/drush" # Full remote path to drush used by ssh
|
|
_update_script="scripts/update.sh"
|
|
_web_dir="web" # Under deploy root, the Drupal public web directory
|
|
_web_excludes='--exclude "/.well-known" --exclude "/sites/default/files" --exclude "/sites/default/settings.*.php'
|
|
# Note: `_php_settings_dir` cannot be included here; Default directly in optionals block
|
|
|
|
#######################################
|
|
# Check for required variables:
|
|
#######################################
|
|
[ -z "${DEPLOY_ENV:-}" ] && DEPLOY_ENV="${CI_ENVIRONMENT_NAME:-}"
|
|
[ -z "${DEPLOY_ENV:-}" ] && { echo 'Missing ENV var: CI_ENVIRONMENT_NAME/DEPLOY_ENV'; exit 1; }
|
|
[ -z "${DEPLOY_ROOT:-}" ] && { echo "Missing ENV var: DEPLOY_ROOT"; exit 1; }
|
|
[ -z "${SSH_TARGET:-}" ] && { echo "Missing ENV var: SSH_TARGET"; exit 1; }
|
|
|
|
#######################################
|
|
# Optional variable setup from defaults:
|
|
#######################################
|
|
[ -z "${BACKUP_DIR:-}" ] && BACKUP_DIR="${_backup_dir}"
|
|
[ -z "${BUILD_ROOT:-}" ] && BUILD_ROOT="./"
|
|
[ -z "${CONFIG_DIR:-}" ] && CONFIG_DIR="${_config_dir}" # NO trailing slash!
|
|
[ -z "${DRUPAL_DIR:-}" ] && DRUPAL_DIR="${_web_dir}" # Name of Drupal public sub-folder
|
|
[ -z "${REMOTE_DRUSH:-}" ] && REMOTE_DRUSH="${_remote_drush}" # Full path to remote drush
|
|
[ -z "${UPDATE_SCRIPT:-}" ] && UPDATE_SCRIPT="${_update_script}"
|
|
[ -z "${WEB_EXCLUDES:-}" ] && WEB_EXCLUDES="${_web_excludes}"
|
|
[ -z "${DRUSH_DISABLE:-}" ] && DRUSH_DISABLE="0"
|
|
[ -z "${UPDATE_DISABLE:-}" ] && UPDATE_DISABLE="0"
|
|
[ -z "${PHP_SETTINGS_DIR:-}" ] && PHP_SETTINGS_DIR="${DRUPAL_DIR}/sites/default"
|
|
|
|
# Be sure to not overwrite any server-only .user.ini
|
|
if [ ! -f ${BUILD_ROOT}/${DRUPAL_DIR}/.user.ini ]; then
|
|
WEB_EXCLUDES="--exclude .user.ini ${WEB_EXCLUDES}"
|
|
fi
|
|
|
|
if [ "${DEBUG:-0}" == "1" ]; then
|
|
#./scripts/show-vars.sh # per-env
|
|
echo "[DEBUG] IN-USE SETTINGS:"
|
|
echo "SSH_TARGET=$SSH_TARGET"
|
|
echo "DEPLOY_ENV=${DEPLOY_ENV}"
|
|
echo "DEPLOY_ROOT=${DEPLOY_ROOT}"
|
|
echo "BUILD_ROOT=${BUILD_ROOT}"
|
|
echo "CONFIG_DIR=${CONFIG_DIR}"
|
|
echo "DRUPAL_DIR=${DRUPAL_DIR}"
|
|
echo "REMOTE_DRUSH=${REMOTE_DRUSH}"
|
|
echo "BACKUP_DIR=${BACKUP_DIR}"
|
|
echo "DRUSH_DISABLE=${DRUSH_DISABLE}"
|
|
echo "UPDATE_SCRIPT=${UPDATE_SCRIPT}"
|
|
echo "UPDATE_DISABLE=${UPDATE_DISABLE}"
|
|
echo "WEB_EXCLUDES=${WEB_EXCLUDES}"
|
|
exit 0
|
|
fi
|
|
|
|
#######################################
|
|
# Functions
|
|
#######################################
|
|
function drush_enabled() {
|
|
if [ "${DRUSH_DISABLE}" == "1" ]
|
|
then
|
|
return 1 #1 is false (so, disabled)
|
|
else
|
|
return 0 #0 is true (enabled) because...bash
|
|
fi
|
|
}
|
|
|
|
#######################################
|
|
# Check drush/site status
|
|
#######################################
|
|
echo "Starting deployment to ${DEPLOY_ENV}"
|
|
drush_enabled || echo "Note: Drush commands are disabled. Commands marked [D] will not execute."
|
|
echo "Verify connectivity (print user & working directory)"
|
|
ssh ${SSH_TARGET} "whoami; pwd"
|
|
echo "[D] Verify drush functionality (cr, status bootstrap)"
|
|
drush_enabled && ssh ${SSH_TARGET} "${REMOTE_DRUSH} cr"
|
|
# Expected good result: "Drupal bootstrap : Successful", otherwise empty (but drush returns 0)
|
|
ssh_cmd="${REMOTE_DRUSH} status --fields=bootstrap"
|
|
drush_enabled && { [[ $(ssh ${SSH_TARGET} "${ssh_cmd}") = *Successful* ]] || { echo ">> Drush failed bootstrap!"; exit 1; } ; }
|
|
|
|
#######################################
|
|
# Enable maintenance mode
|
|
#######################################
|
|
# echo "[D] Set maintenance mode ON"
|
|
# drush_enabled && ssh ${SSH_TARGET} "${REMOTE_DRUSH} state:set system.maintenance_mode TRUE"
|
|
|
|
#######################################
|
|
# Perform a database backup
|
|
#######################################
|
|
backup_file="${DEPLOY_ENV}_$(date +%Y%m%dT%H%M%S).sql.gz"
|
|
ssh_cmd="[ ! -d ${BACKUP_DIR} ] && mkdir -p ${BACKUP_DIR} || true"
|
|
echo "Using backup dir '${BACKUP_DIR}' (created as needed)"
|
|
ssh "${SSH_TARGET}" "$ssh_cmd"
|
|
ssh_cmd="${REMOTE_DRUSH} sql-dump | gzip > ${BACKUP_DIR}/$backup_file"
|
|
echo "[D] Creating backup file ${backup_file}"
|
|
drush_enabled && ssh "${SSH_TARGET}" "${ssh_cmd}"
|
|
|
|
#######################################
|
|
# DEPLOY CODE:
|
|
#######################################
|
|
# Check for sub-dirs...
|
|
ssh_cmd="[ ! -d ${DEPLOY_ROOT}/${CONFIG_DIR} ] && mkdir -p ${DEPLOY_ROOT}/${CONFIG_DIR} || true"
|
|
echo "Ensure '${CONFIG_DIR}' exists"
|
|
ssh "${SSH_TARGET}" "$ssh_cmd"
|
|
ssh_cmd="[ ! -d ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default ] && mkdir -p ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default || true"
|
|
echo "Ensure '${DRUPAL_DIR}/sites/default exists'"
|
|
ssh "${SSH_TARGET}" "$ssh_cmd"
|
|
|
|
# Disable write protect...
|
|
echo "Disabling write protection on settings folder and files."
|
|
ssh_cmd="chmod ug+w ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default/"
|
|
ssh ${SSH_TARGET} ${ssh_cmd}
|
|
ssh_cmd="find ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default/ -maxdepth 1 -type f -name 'settings*php' -exec chmod ug+w '{}' \;"
|
|
ssh ${SSH_TARGET} ${ssh_cmd}
|
|
# Rsync's
|
|
printf "Pushing latest codebase: config…"
|
|
rsync -rz --delete ${BUILD_ROOT}/${CONFIG_DIR}/ ${SSH_TARGET}:${DEPLOY_ROOT}/config
|
|
printf "\b ✓, ${DRUPAL_DIR}…"
|
|
rsync -rz --delete ${WEB_EXCLUDES} ${BUILD_ROOT}/${DRUPAL_DIR}/ ${SSH_TARGET}:${DEPLOY_ROOT}/${DRUPAL_DIR}
|
|
printf "\b ✓, vendor…"
|
|
rsync -rz --delete --links ${BUILD_ROOT}/vendor ${SSH_TARGET}:${DEPLOY_ROOT}/
|
|
printf "\b ✓, scripts…"
|
|
[ -d ./scripts ] && rsync -rz --delete ${BUILD_ROOT}/scripts ${SSH_TARGET}:${DEPLOY_ROOT}/
|
|
printf "\b ✓, composer…"
|
|
scp -q composer.json ${SSH_TARGET}:${DEPLOY_ROOT}/composer.json
|
|
printf "\b ✓, settings…"
|
|
scp -q ${BUILD_ROOT}/${PHP_SETTINGS_DIR}/settings.${DEPLOY_ENV}.php ${SSH_TARGET}:${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default/settings.local.php
|
|
printf "\b ✓\nFile sync complete!\n"
|
|
# Re-protect settings
|
|
echo "Enabling write protection on settings folder and files."
|
|
ssh_cmd="[ -d ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default ] && chmod ug-w ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default/"
|
|
ssh ${SSH_TARGET} ${ssh_cmd}
|
|
ssh_cmd="find ${DEPLOY_ROOT}/${DRUPAL_DIR}/sites/default/ -maxdepth 1 -type f -name 'settings*php' -exec chmod ug-w '{}' \;"
|
|
ssh ${SSH_TARGET} ${ssh_cmd}
|
|
|
|
#######################################
|
|
# [P|re]load database
|
|
#######################################
|
|
if [ ! -z "${PRELOAD_DB_FILE:-}" -a "${DEPLOY_ENV}" != "live" -a "${DEPLOY_ENV}" != "prod" ]; then
|
|
ssh_cmd="${REMOTE_DRUSH} sql-drop -y"
|
|
echo "[D] Dropping existing database"
|
|
drush_enabled && ssh "${SSH_TARGET}" "${ssh_cmd}"
|
|
if drush_enabled; then
|
|
ssh_cmd="${REMOTE_DRUSH} sqlc < ${PRELOAD_DB_FILE}"
|
|
echo "[D] Loading database from ${PRELOAD_DB_FILE}"
|
|
ssh "${SSH_TARGET}" "${ssh_cmd}"
|
|
else
|
|
echo "Fallback: Load database file using mysql (requires .my.cnf)"
|
|
ssh_cmd="mysql < ${PRELOAD_DB_FILE}"
|
|
echo "Loading database from ${PRELOAD_DB_FILE}"
|
|
ssh "${SSH_TARGET}" "${ssh_cmd}"
|
|
fi
|
|
fi
|
|
|
|
#######################################
|
|
# RUN DRUPAL TASKS (via UPDATE_SCRIPT):
|
|
#######################################
|
|
if drush_enabled && [ "${UPDATE_DISABLE}" == "0" -a -f "${BUILD_ROOT}/${UPDATE_SCRIPT}" ]; then
|
|
echo ">> Calling ${UPDATE_SCRIPT} to perform updates..."
|
|
ssh ${SSH_TARGET} "${DEPLOY_ROOT}/${UPDATE_SCRIPT} ${REMOTE_DRUSH}"
|
|
# echo ">> [D] Set maintenance mode OFF"
|
|
# ssh ${SSH_TARGET} ${REMOTE_DRUSH} state:set system.maintenance_mode FALSE
|
|
else
|
|
echo ">> [D] Skipping follow-up drush (cr, updb, cim, etc)."
|
|
# echo ">> Maintenence mode on. To disable: ${drush} state:set system.maintenance_mode FALSE"
|
|
fi
|
|
|
|
echo "Deployment to ${DEPLOY_ENV} completed!"
|