Skip to content

Instantly share code, notes, and snippets.

@chapterjason
Created October 31, 2023 11:16
Show Gist options
  • Save chapterjason/4fffc97203fd0913e2918c13f714f719 to your computer and use it in GitHub Desktop.
Save chapterjason/4fffc97203fd0913e2918c13f714f719 to your computer and use it in GitHub Desktop.

Revisions

  1. chapterjason revised this gist Oct 31, 2023. No changes.
  2. chapterjason created this gist Oct 31, 2023.
    219 changes: 219 additions & 0 deletions plesk-deploy.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,219 @@
    #!/usr/bin/env bash

    set -euo pipefail

    # Base
    USER_DIRECTORY="$(cd ~ && pwd)"
    ROOT_DIRECTORY="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
    LOCK_FILE="${ROOT_DIRECTORY}/.deploy.lock"
    NOW=$(date -u +"%Y%m%d%H%M%S")
    LOG_FILE="${ROOT_DIRECTORY}/.deploy.${NOW}.log"

    # Folder Configuration
    SHARED_DIRECTORY="${ROOT_DIRECTORY}/shared"
    DEPLOYMENT_DIRECTORY="${ROOT_DIRECTORY}/deployment"
    RELEASE_DIRECTORY="${ROOT_DIRECTORY}/release"

    CURRENT_RELEASE_DIRECTORY="${RELEASE_DIRECTORY}/${NOW}"
    CURRENT_DIRECTORY="${ROOT_DIRECTORY}/current"

    # Release Configuration
    SHARED_FILES=".env.local.php"
    SHARED_DIRECTORIES="var/log
    etc/daemons"
    WRITEABLE_DIRECTORIES="var/cache
    var/log"
    EXECUTABLE_FILES="bin/console"
    KEEP_RELEASES=5

    # Variables
    PHP_BIN="${USER_DIRECTORY}/.phpenv/shims/php"
    COMPOSER_BIN="${USER_DIRECTORY}/.phpenv/shims/composer"
    CONSOLE_BIN="${CURRENT_RELEASE_DIRECTORY}/bin/console"

    function after_release() {
    if [ -f "${LOG_FILE}" ] && [ -d "${CURRENT_RELEASE_DIRECTORY}" ]; then
    mv "${LOG_FILE}" "${CURRENT_RELEASE_DIRECTORY}"
    fi
    }

    function __error_handler() {
    EXIT_CODE=$?

    if [ "${EXIT_CODE}" -ne 0 ]; then
    echo "ERROR: Deployment failed. See log file '${LOG_FILE}' for details."
    fi

    if [ -f "${LOCK_FILE}" ]; then
    rm "${LOCK_FILE}"
    fi

    if [ -d "${CURRENT_RELEASE_DIRECTORY}" ]; then
    rm -rf "${CURRENT_RELEASE_DIRECTORY}"
    fi

    exit "${EXIT_CODE}"
    }

    function log() {
    echo "$(date -u +"%Y-%m-%dT%H:%M:%SZ") - $1" | tee -a "${LOG_FILE}"
    }

    function exec_console() {
    "$PHP_BIN" "${CONSOLE_BIN}" "$@"
    }

    # register trap on error
    trap __error_handler ERR INT TERM EXIT

    log "Starting deployment"
    log "PHP: ${PHP_BIN}"
    log "Composer: ${COMPOSER_BIN}"
    log "Console: ${CONSOLE_BIN}"

    # lock deployment
    if [ -f "${LOCK_FILE}" ]; then
    echo "ERROR: Deployment is locked. Please remove the lock file '${LOCK_FILE}' to continue."
    exit 1
    fi

    touch "${LOCK_FILE}"

    # create release directory
    if [ -d "${CURRENT_RELEASE_DIRECTORY}" ]; then
    log "ERROR: Release directory '${CURRENT_RELEASE_DIRECTORY}' already exists."
    exit 1
    fi

    if [ ! -d "${RELEASE_DIRECTORY}" ]; then
    log "Creating release directory '${RELEASE_DIRECTORY}'"
    mkdir -p "${RELEASE_DIRECTORY}"
    fi

    log "Creating release directory '${CURRENT_RELEASE_DIRECTORY}'"
    mv "${DEPLOYMENT_DIRECTORY}" "${CURRENT_RELEASE_DIRECTORY}"
    mkdir "${DEPLOYMENT_DIRECTORY}"

    # add symlinks of shared files/dirs
    for FILE in ${SHARED_FILES}; do
    SOURCE_FILE="${SHARED_DIRECTORY}/${FILE}"
    TARGET_FILE="${CURRENT_RELEASE_DIRECTORY}/${FILE}"
    SOURCE_DIRECTORY="$(dirname "${SOURCE_FILE}")"
    TARGET_DIRECTORY="$(dirname "${TARGET_FILE}")"

    if [ ! -f "${SOURCE_FILE}" ]; then
    log "WARNING: Shared file '${SOURCE_FILE}' does not exist. Creating empty file."
    mkdir -p "${SOURCE_DIRECTORY}"
    touch "${SOURCE_FILE}"
    fi

    if [ -f "${TARGET_FILE}" ]; then
    log "WARNING: Removing existing file '${TARGET_FILE}'"
    rm "${TARGET_FILE}"
    fi

    if [ ! -d "${TARGET_DIRECTORY}" ]; then
    log "WARNING: Target directory '${TARGET_DIRECTORY}' does not exist. Creating empty directory."
    mkdir -p "${TARGET_DIRECTORY}"
    fi

    log "Symlinking file '${SOURCE_FILE}' to '${TARGET_FILE}'"
    ln -s "${SOURCE_FILE}" "${TARGET_FILE}"
    done

    for DIRECTORY in ${SHARED_DIRECTORIES}; do
    SOURCE_DIRECTORY="${SHARED_DIRECTORY}/${DIRECTORY}"
    TARGET_DIRECTORY="${CURRENT_RELEASE_DIRECTORY}/${DIRECTORY}"
    TARGET_PARENT_DIRECTORY="$(dirname "${TARGET_DIRECTORY}")"

    if [ ! -d "${SOURCE_DIRECTORY}" ]; then
    log "WARNING: Shared directory '${SOURCE_DIRECTORY}' does not exist. Creating empty directory."
    mkdir -p "${SOURCE_DIRECTORY}"
    fi

    if [ -d "${TARGET_DIRECTORY}" ]; then
    log "WARNING: Removing existing directory '${TARGET_DIRECTORY}'"
    rm -rf "${TARGET_DIRECTORY}"
    fi

    if [ ! -d "${TARGET_PARENT_DIRECTORY}" ]; then
    log "WARNING: Target parent directory '${TARGET_PARENT_DIRECTORY}' does not exist. Creating empty directory."
    mkdir -p "${TARGET_PARENT_DIRECTORY}"
    fi

    log "Symlinking directory '${SOURCE_DIRECTORY}' to '${TARGET_DIRECTORY}'"
    ln -s "${SOURCE_DIRECTORY}" "${TARGET_DIRECTORY}"
    done

    # make dirs writeable
    for DIRECTORY in ${WRITEABLE_DIRECTORIES}; do
    TARGET_DIRECTORY="${CURRENT_RELEASE_DIRECTORY}/${DIRECTORY}"

    if [ ! -d "${TARGET_DIRECTORY}" ]; then
    log "WARNING: Writeable directory '${TARGET_DIRECTORY}' does not exist. Creating empty directory."
    mkdir -p "${TARGET_DIRECTORY}"
    fi

    log "Making directory '${TARGET_DIRECTORY}' writeable"
    chmod -R 777 "${TARGET_DIRECTORY}"
    done

    # make files executable
    for FILE in ${EXECUTABLE_FILES}; do
    TARGET_FILE="${CURRENT_RELEASE_DIRECTORY}/${FILE}"

    if [ ! -f "${TARGET_FILE}" ]; then
    log "WARNING: Executable file '${TARGET_FILE}' does not exist."
    exit 1
    fi

    log "Making file '${TARGET_FILE}' executable"
    chmod +x "${TARGET_FILE}"
    done

    log "Installing vendors"
    "${COMPOSER_BIN}" install --no-interaction --no-dev --optimize-autoloader

    log "Clearing cache"
    exec_console cache:clear --no-interaction --no-warmup --env=prod

    log "Warming up cache"
    exec_console cache:warmup --no-interaction --env=prod

    log "Installing assets"
    exec_console assets:install --no-interaction --env=prod

    log "Migrating database"
    exec_console doctrine:migrations:migrate --allow-no-migration --all-or-nothing --no-interaction --env=prod

    log "Symlinking release '${CURRENT_RELEASE_DIRECTORY}' to '${CURRENT_DIRECTORY}'"

    if [ -L "${CURRENT_DIRECTORY}" ] || [ -d "${CURRENT_DIRECTORY}" ]; then
    log "Removing existing symlink '${CURRENT_DIRECTORY}'"
    rm "${CURRENT_DIRECTORY}"
    fi

    ln -s "${CURRENT_RELEASE_DIRECTORY}" "${CURRENT_DIRECTORY}"

    log "Reloading workers"
    exec_console worker:reload --env=prod --no-interaction

    log "Restarting workers"
    exec_console messenger:stop-workers --env=prod --no-interaction

    # unlock deployment
    log "Removing lock file '${LOCK_FILE}'"
    rm "${LOCK_FILE}"

    # cleanup (remove old release (keep settings))
    RELEASES="$(ls -dt "${RELEASE_DIRECTORY}/"*)"
    RELEASES="$(echo "${RELEASES}" | tail -n +$((KEEP_RELEASES + 1)))"

    for RELEASE in ${RELEASES}; do
    log "Removing old release '${RELEASE}'"
    rm -rf "${RELEASE}"
    done

    log "Deployment finished"

    after_release